2

我正在尝试来自 Python Lexical closures问题中的一段代码

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是一个模块范围变量,只有在您的第二个示例中,您才通过将代码包装在新函数中来引入新范围actualFact

于 2012-05-30T11:12:21.727 回答
2

语言参考指定为“func_closure无或包含函数自由变量绑定的单元格元组”。

现在,请注意您的两个版本之间的区别:在第一个版本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 回答