15

I am wondering how I can access a function inside another function. I saw code like this:

>>> def make_adder(x):
      def adder(y):
        return x+y
      return adder
>>> a = make_adder(5)
>>> a(10)
15

So, is there another way to call the adder function? And my second question is why in the last line I call adder not adder(...)?

Good explanations are much appreciated.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
ovrwngtvity
  • 4,261
  • 3
  • 15
  • 20
  • equivalent: `make_adder = lambda x : lambda y: x+y` now, can you call the inner `lambda` ? – Elazar Jun 30 '13 at 22:29
  • yeah! `make_adder = make_adder(...)`, then `make_adder(...)` – ovrwngtvity Jul 06 '13 at 23:18
  • Which is, no, you can't. – Elazar Jul 07 '13 at 14:03
  • I do not understand your question. You ask if you can call the `adder` function, but yes, you've done it in `a(10)` line. In the "`return`" line, you do not *call* `adder`, you *return* it. Sorry for being obvious. – Alexey Feb 24 '18 at 21:49

6 Answers6

31

You really don't want to go down this rabbit hole, but if you insist, it is possible. With some work.

The nested function is created anew for each call to make_adder():

>>> import dis
>>> dis.dis(make_adder)
  2           0 LOAD_CLOSURE             0 (x)
              3 BUILD_TUPLE              1
              6 LOAD_CONST               1 (<code object adder at 0x10fc988b0, file "<stdin>", line 2>)
              9 MAKE_CLOSURE             0
             12 STORE_FAST               1 (adder)

  4          15 LOAD_FAST                1 (adder)
             18 RETURN_VALUE        

The MAKE_CLOSURE opcode there creates a function with a closure, a nested function referring to x from the parent function (the LOAD_CLOSURE opcode builds the closure cell for the function).

Without calling the make_adder function, you can only access the code object; it is stored as a constant with the make_adder() function code. The byte code for adder counts on being able to access the x variable as a scoped cell, however, which makes the code object almost useless to you:

>>> make_adder.__code__.co_consts
(None, <code object adder at 0x10fc988b0, file "<stdin>", line 2>)
>>> dis.dis(make_adder.__code__.co_consts[1])
  3           0 LOAD_DEREF               0 (x)
              3 LOAD_FAST                0 (y)
              6 BINARY_ADD          
              7 RETURN_VALUE        

LOAD_DEREF loads a value from a closure cell. To make the code object into a function object again, you'd have to pass that to the function constructor:

>>> from types import FunctionType
>>> FunctionType(make_adder.__code__.co_consts[1], globals(),
...              None, None, (5,))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: arg 5 (closure) expected cell, found int

but as you can see, the constructor expects to find a closure, not an integer value. To create a closure, we need, well, a function that has free variables; those marked by the compiler as available for closing over. And it needs to return those closed over values to us, it is not possible to create a closure otherwise. Thus, we create a nested function just for creating a closure:

def make_closure_cell(val):
    def nested():
        return val
    return nested.__closure__[0]

cell = make_closure_cell(5)

Now we can recreate adder() without calling make_adder:

>>> adder = FunctionType(make_adder.__code__.co_consts[1], globals(),
...                      None, None, (cell,))
>>> adder(10)
15

Perhaps just calling make_adder() would have been simpler.

Incidentally, as you can see, functions are first-class objects in Python. make_adder is an object, and by adding (somearguments) you invoke, or call the function. In this case, that function returns another function object, one that you can call as well. In the above tortuous example of how to create adder() without calling make_adder(), I referred to the make_adder function object without calling it; to disassemble the Python byte code attached to it, or to retrieve constants or closures from it, for example. In the same way, the make_adder() function returns the adder function object; the point of make_adder() is to create that function for something else to later call it.

The above session was conducted with compatibility between Python 2 and 3 in mind. Older Python 2 versions work the same way, albeit that some of the details differ a little; some attributes have different names, such as func_code instead of __code__, for example. Look up the documentation on these in the inspect module and the Python datamodel if you want to know the nitty gritty details.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Just wondering: is `__code__` portable across implementations, or CPython-specific? –  Jun 30 '13 at 22:33
  • @rightfold: From the [glossary on bytecode](http://docs.python.org/2/glossary.html#term-bytecode): *Python source code is compiled into bytecode, the internal representation of a Python program in the CPython interpreter.*. Jython and IronPython do have `func_code` attributes but I do not know what that contains. – Martijn Pieters Jun 30 '13 at 22:40
  • "You really don't want to go down this rabbit hole, but if you insist, it is possible" This made me laugh. This was a very detailed explanation as well. – coder543 Jul 01 '13 at 00:42
  • Very nice exposé of the guts of CPython. @rightfold: shorter version of Martijn's answer is, "not portable, CPython-specific". Jython no doubt uses Java's internal machinery, and IronPython no doubt uses .NET's C# machinery. It's likely that there's some very similar sneakiness you could use in each one, because they're all trying to achieve the same results, but it's unlikely they'd match up enough to "spell them the same", as it were. – torek Jul 01 '13 at 01:13
7

No, you can't call it directly as it is a local variable to make_adder.

You need to use adder() because return adder returned the function object adder when you called make_adder(5). To execute this function object you need ()

def make_adder(x):
       def adder(y):
           return x+y
       return adder
... 
>>> make_adder(5)             #returns the function object adder
<function adder at 0x9fefa74>

Here you can call it directly because you've access to it, as it was returned by the function make_adder. The returned object is actually called a closure because even though the function make_addr has already returned, the function object adder returned by it can still access the variable x. In py3.x you can also modify the value of x using nonlocal statement.

>>> make_adder(5)(10)          
15

Py3.x example:

>>> def make_addr(x):
        def adder(y):
                nonlocal x
                x += 1
                return x+y
        return adder
... 
>>> f = make_addr(5)
>>> f(5)               #with each call x gets incremented
11
>>> f(5)
12

#g gets it's own closure, it is not related to f anyhow. i.e each call to 
# make_addr returns a new closure.
>>> g = make_addr(5)  
>>> g(5)
11 
>>> g(6)
13
IgnisErus
  • 386
  • 1
  • 5
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Worth noting: because Python 2.x lacks "nonlocal", you can't change your non-local variables as simply. However, you can still make modifiable values using lists (I'll add an answer below showing this). – torek Jul 01 '13 at 01:22
4

You are returning the function adder to the caller, not the result of calling it, hence the absence of parentheses.

Because make_adder returns adder, you already have direct access to adder. In fact, a(10) is actually a call to adder(10).

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
1

As an addendum to @AshwiniChaudhary's answer, you can emulate Python 3.x's nonlocal with modifiable objects. For instance:

def counter(name):
    x = [0]
    def inc(n):
        x[0] += n
        print "%s: %d" % (name, x[0])
    return inc

spam = counter('spams')
ham = counter('hams')

spam(3)
ham(1)
spam(1)
ham(2)

In python2.7 this produces:

$ python closure.py
spams: 3
hams: 1
spams: 4
hams: 3

The reason for using x[0] is that attempts to reassign x create a new local-to-inc x:

def counter(name):
    x = 0
    def inc(n):
        x += n # this doesn't work!
        print "%s: %d" % (name, x[0])
    return inc

Attempting to use this produces:

Traceback (most recent call last):
  File "closure.py", line 11, in <module>
    spam(3)
  File "closure.py", line 4, in inc
    x += n
UnboundLocalError: local variable 'x' referenced before assignment

The remaining obvious thing, an attempt to use global, also fails as it tries to access a module-level x instead of the one inside counter. (This is why nonlocal was added in the first place!)

One other point on closures: they're mechanically transformable to / from classes with instance variables. Instead of defining counter as above, I could make a class:

class Counter(object):
    def __init__(self, name):
        self.name = name
        self.x = 0
    def inc(self, n):
        self.x += n
        print "%s: %d" % (self.name, self.x)

and then use it as:

spam = Counter('spams')
spam.inc(3)

for instance. Should you want to preserve the call syntax, Python permits this: instead of defining inc(self, n), define __call__(self, n)—or define __call__ as invoking inc, giving rise to:

class Counter(object):
    def __init__(self, name):
        self.name = name
        self.x = 0
    def inc(self, n):
        self.x += n
        print "%s: %d" % (self.name, self.x)
    __call__ = inc

spam = Counter('spams')
ham = Counter('hams')

spam.inc(3)
ham.inc(1)
spam(1)
ham(2)

which shows the somewhat schizophrenic "two ways to call it" interface in the class. :-)

torek
  • 448,244
  • 59
  • 642
  • 775
0

I'm not sure this helps, but you can use the __call__ boilerplate to simulate the behavior you're looking for. For example:

class MakeAdder:
    def __init__(self, x):
        self.x = x

    def __call__(self, y):
        return self.x + y



a = MakeAdder(5)
a(10)
15

daleadil
  • 1
  • 2
0

My two cents:

def testFn(Inner=0):
    
    def subFunct():
        print ('SubFunct Executed')
    
    if Inner:
        return subFunct
        
        
    print ('Regular Exec')
        

testFn(Inner=1)()

This function accepts one parameter which has default value of 0, When set to True, the parent function returns the object of the inner function. The object, being a function, is callable, and is called with '()' :

'testFn(Inner=1)' will return the inner function object

'()' will call it
Bob
  • 11
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the [help center](https://stackoverflow.com/help/how-to-answer). – MagnusO_O Oct 14 '22 at 11:53