1.原始问题：How to access a function inside a function?
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
Good explanations are much appreciated.
No, you can’t call it directly as it is a local variable to
You need to use
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
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
>>> make_adder(5)(10) 15
>>> 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
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
>>> import dis >>> dis.dis(make_adder) 2 0 LOAD_CLOSURE 0 (x) 3 BUILD_TUPLE 1 6 LOAD_CONST 1 (
", line 2>) 9 MAKE_CLOSURE 0 12 STORE_FAST 1 (adder) 4 15 LOAD_FAST 1 (adder) 18 RETURN_VALUE
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,
", line 2>) >>> dis.dis(make_adder.__code__.co_consts) 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, globals(), ... None, None, (5,)) Traceback (most recent call last): File "
", line 1, in 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__ cell = make_closure_cell(5)
Now we can recreate
adder() without calling
>>> adder = FunctionType(make_adder.__code__.co_consts, 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.
You are returning the function
adder to the caller, not the result of calling it, hence the absence of parentheses.
adder, you already have direct access to
adder. In fact,
a(10) is actually a call to
As an addendum to @AshwiniChaudhary's answer, you can emulate Python 3.x's nonlocal with modifiable objects. For instance:
def counter(name): x =  def inc(n): x += n print "%s: %d" % (name, x) 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 is that attempts to reassign
x create a new local-to-
def counter(name): x = 0 def inc(n): x += n # this doesn't work! print "%s: %d" % (name, x) return inc
Attempting to use this produces:
Traceback (most recent call last): File "closure.py", line 11, in
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. 🙂