2013-01-19 11 views
24

ビーズリーPG 100は言及:obj .__ closure__には正確に何が入っていますか?

>>>python.__closure__ 
(<cell at 0x67f50: str object at 0x69230>,) 
>>>python.__closure__[0].cell_contents 

私の理解では__closure__がリストであるが、すべてこの の細胞のものとstrオブジェクトが何ということです?それは1-aryタプルのように見えますか?

答えて

29

閉鎖セルは、関数が必要とする値を参照しますが、周囲のスコープから取得します。

Pythonはネストされた関数をコンパイルするとき、ネストされた関数と親スコープの両方のコードオブジェクト内の親関数(グローバルではありません)でのみ参照される変数を書き留めます。これらは、それぞれ、これらの関数の__code__オブジェクトのco_freevarsおよびco_cellvars属性です。

親関数が実行されるときにネストされた関数を作成すると、これらの参照がネストされた関数にクロージャを付加するために使用されます。

関数クロージャは、空き変数(co_freevarsという名前)ごとに1つのセルのタプルを保持します。セルは親スコープのローカル変数への特別な参照で、それらのローカル変数が指す値に従います。これは、最良の例で示されている:上記の例で

def foo(): 
    def bar(): 
     print(spam) 

    spam = 'ham' 
    bar() 
    spam = 'eggs' 
    bar() 
    return bar 

b = foo() 
b() 

、機能bar関数foospamを指し示す1つの閉鎖セルを有しています。セルはspamの値に従います。さらに重要なことに、が表示されてからbarが返されると、spamfooに存在しなくても、セルは値(文字列eggs)を参照し続けます。

従って、上記のコード出力:

>>> b=foo() 
ham 
eggs 
>>> b() 
eggs 

b.__closure__[0].cell_contents'eggs'あります。

bar()がと呼ばれるとき、クロージャは逆参照されます。。クロージャはここで値を取得しません。すべての3つのlambda機能がspam変数を参照するので、

def foo(): 
    bar = [] 
    for spam in ('ham', 'eggs', 'salad'): 
     bar.append(lambda: spam) 
    return bar 

for bar in foo(): 
    print bar() 

上記行にsalad三回を印刷する:つまり、ループ変数を参照する(lambda式またはdefステートメントで)ネストされた関数を生成する際に違いが関数オブジェクトが作成されたときにバインドされた値ではありません。 forループが終了するまでには、spam'salad'にバインドされていたため、3つのクロージャはすべてその値に解決されます。

4

古いfunc_closureの新しいPython 3の名前です。

http://docs.python.org/3.0/whatsnew/3.0.html

func_Xという名前の関数属性は、ユーザー定義の属性の機能属性の名前空間でこれらの名前を解放し、__X__フォームを使用するために名前が変更されました。ウィット、func_closurefunc_codefunc_defaultsfunc_dictfunc_docfunc_globalsに、func_nameは、それぞれ、__closure____code____defaults____dict____doc____globals____name__と改名されました。一言で言えば

__closure__Noneまたは関数の自由変数のバインディング含む細胞のtupleです。

また、書き込み不可能です。

参考:fooとして

>>> 
['I am free', 'I am free too'] 

使用している機能barを返して:出力がhttp://docs.python.org/ref/types.html

パイソン< 3(私はfunc_closureを使用しています)

def foo(): 
    x = "I am used" 
    y = "I am free" 
    z = "I am free too" 

    def bar(x): 
     return x, y, z 

    return bar 

c = foo().func_closure 

print [i.cell_contents for i in c] 

それ自身の価値xであるが、yまたはzではない。したがって、彼らは__closure__になります。

1
>>> def f(): 
...  a = "HELO" 
...  b = 1.0 
...  def w(c): 
...   return a,b,c 
...  return w 

>>> w = f() 
>>> w.__closure__ 
(<cell at 0xa05c4ac: str object at 0x9e91b74>, <cell at 0xa05c3bc: float object at 0xb733dde8>) 
>>> w.__closure__[0].cell_contents 
'HELO' 
>>> w.__closure__[1].cell_contents 
1.0 

私はどこにも使用さセルタイプを見たことがありません。クロージャ変数を保持するのは目的に合っているようです。

関連する問題