44

Beazley pg 100 は次のように述べています。

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

私の理解では、それ__closure__はリストですが、このセルのものと str オブジェクトは何ですか?? 1 項タプルのように見えますか?

4

4 に答える 4

68

クロージャ セルは、関数に必要な値を参照しますが、周囲のスコープから取得されます。

Python がネストされた関数をコンパイルするとき、それが参照するが、ネストされた関数と親スコープの両方のコード オブジェクト内の親関数 (グローバルではない) でのみ定義されている変数を記録します。これらは、それぞれこれらの関数のオブジェクトのco_freevarsおよびco_cellvars属性です。__code__

次に、ネストされた関数を実際に作成すると (これは親関数が実行されたときに発生します)、それらの参照を使用して、ネストされた関数にクロージャーをアタッチします。

関数クロージャはセルのタプルを保持し、各自由変数 ( で名前が付けられていますco_freevars) ごとに 1 つずつです。セルは、親スコープのローカル変数への特別な参照であり、ローカル変数が指す値に従います。これは、次の例で最もよく説明されています。

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

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

b = foo()
b()

上記の例では、関数barには 1 つのクロージャ セルがあり、関数内で を指してspamいますfoo。セルは の値に従いますspam。さらに重要なことは、 がfoo()完了して返されると、セル内の変数が存在しなくなってもbar、セルは引き続き値 ( string ) を参照します。eggsspamfoo

したがって、上記のコードは次を出力します。

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

b.__closure__[0].cell_contentsです'eggs'

が呼び出されると、クロージャが逆参照されることに注意してくださいbar()。クロージャーはここで値をキャプチャしません。これは、ループ変数を参照するネストされた関数 (lambda式またはステートメントを使用)を生成するときに違いがあります。def

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

for bar in foo():
    print bar()

上記は、関数オブジェクトが作成されたときにバインドされた値ではなく、 3 つの関数saladすべてが変数を参照するため、3 回続けて出力されます。ループが終了するまでにはにバインドされているため、3 つのクロージャすべてがその値に解決されます。lambdaspamforspam'salad'

于 2013-01-19T12:59:54.690 に答える
11

これは、古いの新しいPython3の名前ですfunc_closure

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

指定された関数属性は、フォームfunc_Xを使用するように名前が変更され__X__、ユーザー定義属性の関数属性名前空間でこれらの名前が解放されました。ウィットに、、、、、、、、は、func_closureそれぞれ、、、、、、、、に名前が変更されました。func_codefunc_defaultsfunc_dictfunc_docfunc_globalsfunc_name__closure____code____defaults____dict____doc____globals____name__

一言で言えば:

__closure__関数の自由変数のバインディングを含むセルのまたはNonea 。tuple

また、書き込み可能ではありません。

参照:http ://docs.python.org/ref/types.html

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

出力:

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

独自の値を使用してfooいる関数を返していますが、またはは返していません。だから、彼らは下に入る。barxyz__closure__

于 2013-01-19T11:51:38.853 に答える
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

他の場所で使用されている細胞型を見たことがありません。クロージャー変数を保持する目的で構築されているようです。

于 2013-01-19T11:56:58.627 に答える