4
def myFunc( a, b ):
  def innerFunc( c ):
    print c
  innerFunc( 2 )
  print a, b

How can I access the inner function directly? I want the object/address of that function in the format

<function innerFunc at 0xa0d5fb4>

I tried with myFunc._getattr_( 'innerFunc' ) but that didn't work.

crk
  • 617
  • 1
  • 8
  • 12
  • 2
    Why do you want to do this? If want to use `innerFunc` outside `myFunc` then either move `innerFunc` outside `myFunc` or return it from `myFunc`. I can't think of any sane reason to do this. – Peter Graham Jun 25 '12 at 23:55

4 Answers4

5

As the function does not exists until the function call (and only exists during it), you cannot access it.

If the closure is not important, you can build the inner function directly from the code constant placed inside the outer function:

inner = types.FunctionType(myFunc.__code__.co_consts[1], globals())

The position inside the const values of the function may vary...

This solution does not require calling myFunc.

JBernardo
  • 32,262
  • 10
  • 90
  • 115
  • 1
    +1 for teaching me about `__code__` though it is an internal property so Im not sure if I can always do this, thanks anyway. – Samy Vilar Jun 26 '12 at 00:22
  • 1
    The code object is also available through the function's `func_code` attribute. – mkarasek Jun 26 '12 at 00:26
4

what you could do is either return the function or attach it to its parent when called ...

>>> def myFunc( a, b ):
...     def innerFunc( c ):
...         print c
...     innerFunc( 2 )
...     myFunc.innerFunc = innerFunc
...     print a, b
...
>>>
>>> myFunc(1,2)
2
1 2
>>> myFunc.innerFunc(3)
3
>>> 

though apparently you can access the source code using a special attribute, that function objects have ... myFunc.func_code though this seems to be accessing some serious stuff

>>> help(myFunc.func_code)
 Help on code object:
 class code(object)
  |  code(argcount, nlocals, stacksize, flags, codestring, constants, names,
  |        varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])
  |  
  |  Create a code object.  Not for the faint of heart.
  |


Samy Vilar
  • 10,800
  • 2
  • 39
  • 34
  • 3
    There's nothing wrong with adding attributes to functions: That's how decorators are written. The problem on this solution is that you **need** to call the outer function before (maybe you can't afford that on real code). – JBernardo Jun 25 '12 at 23:49
  • 1
    @JBernardo python doesn't really have `private` attributes as such you can quite easily override the internal structure that can lead to subtle bugs or undefined behavior, as for `That's how decorators are written` I have no idea what you mean decorators are nothing more than function wrappers heres a good example: http://stackoverflow.com/questions/739654/understanding-python-decorators unless Im wrong. – Samy Vilar Jun 25 '12 at 23:57
  • Do you realize `function` is the only builtin type which lets you do that? Maybe there's a reason, don't you think? Try adding an attribute to a string or a dict. – JBernardo Jun 26 '12 at 00:05
  • I thought it was because functions are actually `objects` in python as such you can attach anything to them like the other type of objects. but yes I can't seem to do the same thing to other types did notice the other types don't seem to have `__dict__` though not sure why python was designed this way, it maybe due to the pythonic philosophy of namespaces ... – Samy Vilar Jun 26 '12 at 00:19
  • "Python has lazy evaluation..." Errr... what? Python most definitely does not have lazy evaluation (except for generators, arguably). Things within a function don't exist outside of it because they may depend on the function's arguments, which aren't defined outside of the function. That has nothing to do with lazy evaluation. Lazy evaluation means that even when you call the function, it isn't evaluated unless its result is actually used. – Ben Jun 26 '12 at 01:30
2

You can't. The inner function doesn't exist until the outer function is called, and is decref'ed when the outer function exits, which in this case means that it ceases to exist.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
2

You can't call innerFunc directly from outside of myFunc because it's inside myFunc's namespace. One way to call innerFunc is by returning the innerFunc object from myFunc

like this:

def myFunc( a, b ):
  def innerFunc( c ):
    print c
  print a, b
  return innerFunc #return the innerFunc from here

x=myFunc(1,2)
x(3) # calling x now calls innerFunc
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504