2

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?

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

0

look at http://docs.python.org/2/reference/executionmodel.html#naming-and-binding.It contains explanations about scops.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.