closure
is often used as function factory, one example being:
>>> def maker(N):
... def action(X):
... return X ** N
... return action
...
>>> f = maker(2)
>>> f(3)
9
lambda version:
>>> def maker(N):
... return lambda X: X ** N
...
>>> f = maker(2)
>>> f(3)
9
the use of closure
could extend the use of inner function outside its scope, in the example, the inner function action
.
the detail of this state retention process: http://www.cnblogs.com/ChrisChen3121/p/3208119.html
how to read the output from dis.dis
:
1. https://stackoverflow.com/questions/12673074/how-should-i-understand-the-output-of-dis-dis
2. http://www.goldsborough.me/python/low-level/2016/10/04/00-31-30-disassembling_python_bytecode/
3. https://docs.python.org/3.5/library/dis.html#python-bytecode-instructions
>>> def maker(N):
... def action(X):
... return X ** N
... return action
...
>>> maker.__code__
<code object maker at 0x7fe5104f2030, file "<stdin>", line 1>
>>> import dis
>>> dis.dis(maker.__code__)
2 0 LOAD_CLOSURE 0 (N)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object action at 0x7fe5186e39c0, file "<stdin>", line 2>)
9 LOAD_CONST 2 ('maker.<locals>.action')
12 MAKE_CLOSURE 0
15 STORE_FAST 1 (action)
4 18 LOAD_FAST 1 (action)
21 RETURN_VALUE
>>> f = maker(2)
>>> f.__closure__
(<cell at 0x7fe518708318: int object at 0x7fe518674980>,)
>>> dir(f.__closure__[0])
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
>>> f.__closure__[0]
<cell at 0x7fe518708318: int object at 0x7fe518674980>
>>> f.__closure__[0].cell_contents
2
One thing should be cared is using loop to create nested functions inside a loop.
>>> def maker(N):
... acts = []
... for i in range(N):
... acts.append(lambda X: X ** i)
... return acts
...
>>> flist = maker(3)
>>> for f in flist:
... print(f(2))
...
4
4
4
The reason is all the lambda functions reference the value bounded only when called - the value i is 2.
Use default argument to solve this
>>> def maker(N):
... acts = []
... for i in range(N):
... acts.append(lambda X, i=i: X ** i)
... return acts
...
>>> flist = maker(3)
>>> for f in flist:
... print(f(2))
...
1
2
4