2

デモの例があります:

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)

内部関数が呼び出されている間、どのようにして の値を知っているのだろうかfunc。内部関数と外部関数のスコープはどのように接続されていますか?

4

2 に答える 2

3

コンパイラはそれらを接続します。

と をコンパイルするouterinner、 のfunc名前outerはクロージャとしてマークされ、 では自由変数としてマークされますinner。実行時に、インタープリターはfunc名前outerへの参照をinnerクロージャ セルとして関数オブジェクトにアタッチすることを認識します。

バイトコードの逆アセンブルで結果を確認できます。

>>> 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        

は、使用するために名前をクロージャーでLOAD_CLOSUREラップします。タプルとして付加されたクロージャ セルを持つ関数オブジェクトを ( でロードされたバイト コード オブジェクトから) 構築します。では、オペコードがクロージャから値をロードします。funcinnerMAKE_CLOSURELOAD_CONSTinnerLOAD_DEREFfunc

innerクロージャーは、結果の関数オブジェクトで見つけることができます。

>>> 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>

したがって、inner関数オブジェクトは、後で逆参照するためにクロージャを持ちます。

于 2013-08-08T13:27:02.047 に答える
0

http://docs.python.org/2/reference/executionmodel.html#naming-and-bindingを見てください。スコープに関する説明が含まれています。

于 2013-08-08T13:32:36.067 に答える