2

Pythonの字句クロージャの質問からコードを試しています

flist = []
for i in xrange(3):
    def func(x): return x*i
    flist.append(func)

for f in flist:
    print f.func_closure

出力は次のとおりです。

None
None
None

すべきではないですか?:

(<cell at 0x9222d94: int object at 0x8cabdbc>,)
(<cell at 0x9222d94: int object at 0x8cabdbc>,)
(<cell at 0x9222d94: int object at 0x8cabdbc>,)

次のコードを使用して上記の出力を取得しました。

flist = []
def actualFact():
    for i in xrange(3):
        def func(x): return x * i
        flist.append(func)

for f in flist:
    print f.func_closure

Python 2.6.6(r266:84292、2010年9月15日、15:52:39)を使用しています。

4

3 に答える 3

4

クロージャーは、グローバル (モジュール) スコープの外で参照される変数がある場合にのみ導入されます。

>>> def foo():
...     def bar(): pass
...     return bar
...
>>> foo().func_closure is None
True
>>> spam = 'eggs'
>>> def foo():
...     def bar(): return spam
...     return bar
...
>>> foo().func_closure is None
True

内部関数が周囲のスコープ内の変数を参照する場合にのみ、クロージャーが生成されます。

>>> def foo():
...     spam = 'eggs'
...     def bar(): return spam
...     return bar
...
>>> foo().func_closure is None
False
>>> foo().func_closure
(<cell at 0x108472718: str object at 0x108471de0>,)

実際には、周囲のスコープ内の変数を参照する必要があることに注意してください。単にスコープを無視すると、次のようNoneになります。

>>> def foo():
...     spam = 'eggs'
...     def bar(): pass
...     return bar
...
>>> foo().func_closure is None
True

最初の例でiは、モジュール スコープ変数です。2 番目の例でのみ、コードを new function にラップして新しいスコープを導入しますactualFact

于 2012-05-30T11:12:21.727 に答える
2

言語リファレンスでは、func_closure「関数の自由変数のバインディングを含むセルがないか、セルのタプル」であると指定されています。

ここで、2つのバージョンの違いに注意してください。最初のバージョンiでは、モジュールレベル(つまりグローバル)の変数です。各関数を評価した結果は同じです。

>>> [f(2) for f in flist]
[4, 4, 4]

各関数でiは、は無料ではありませんが、グローバルを参照しているiため、出力はゼロ以外の長さのタプルのリストであってはなりません。

func_closure実際には、かなり深い魔法を使っていない限り、おそらく、の値は気にしないでしょう。魔法のようなことをしている場合、仕様を考えると、自由変数がない場合に空のタプルであってはならない理由func_closureはないようです。コードを異なるもの間で移植できるようにする場合は、その場合を適切に処理してください。 pythonのポイントバージョン。

于 2012-05-30T11:09:33.883 に答える
1

閉鎖せずにこれを行う安価な方法

for i in xrange(3):
    def func(x, i=i): return x*i
    flist.append(func)
于 2012-05-30T11:12:33.797 に答える