Reputation: 163
I have a demo example:
def outer(func):
def inner(foo):
arg_inner=some_value
func(arg_inner,foo)
return inner
def third_party(arg1,arg2):
#do something
final = outer(third_party)
final(3)
I wonder how comes the inner function knows the value of func
while being called. How the scope of inner function and outer are connected?
Upvotes: 2
Views: 106
Reputation: 1122142
The compiler connects them.
When compiling outer
and inner
, the func
name in outer
is marked as a closure, and a free variable in inner
. On execution, the interpreter then knows to attach a reference to the func
name from outer
to the inner
function object as a closure cell.
You can see the result in the disassembly of the bytecode:
>>> import dis
>>> dis.dis(outer)
2 0 LOAD_CLOSURE 0 (func)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object inner at 0x1079a5ab0, file "<stdin>", line 2>)
9 MAKE_CLOSURE 0
12 STORE_FAST 1 (inner)
4 15 LOAD_FAST 1 (inner)
18 RETURN_VALUE
>>> inner = outer(lambda a, b: None)
>>> dis.dis(inner)
3 0 LOAD_DEREF 0 (func)
3 LOAD_GLOBAL 0 (arg_inner)
6 LOAD_FAST 0 (foo)
9 CALL_FUNCTION 2
12 POP_TOP
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
The LOAD_CLOSURE
wraps the func
name in a closure for inner
to use; MAKE_CLOSURE
builds a function object (from the byte code object loaded with LOAD_CONST
) with attached closure cells as a tuple. In inner
, the LOAD_DEREF
opcode loads the value from the func
closure.
The closure can be found back on the resulting inner
function object:
>>> inner.func_closure
(<cell at 0x107a25a28: function object at 0x107a28b18>,)
>>> inner.func_code.co_freevars
('func',)
>>> inner.func_closure[0].cell_contents
<function <lambda> at 0x107a28b18>
so the inner
function object carries the closure with it for later dereferencing.
Upvotes: 3
Reputation: 1585
look at http://docs.python.org/2/reference/executionmodel.html#naming-and-binding.It contains explanations about scops.
Upvotes: 0