是否有Pythonic方法来关闭循环变量?

时间:2012-01-20 19:32:50

标签: python for-loop closures

我刚刚通过SO跑过Eric Lippert的Closing over the loop variable considered harmful,经过实验,意识到在Python中存在同样的问题(并且更难以解决)。

>>> l = []
>>> for r in range(10):
...   def foo():
...      return r
...   l.append(foo)
...
>>> for f in l:
...   f()
...
9
9
9
# etc

并且,标准的C#解决方法不起作用(我假设因为Python中引用的性质)

>>> l = []
>>> for r in range(10):
...   r2 = r
...   def foo():
...      return r2
...   l.append(foo)
...
>>> for f in l:
...   f()
...
9
9
9
# etc

我认识到这在Python中并不是一个问题,它一般强调非闭包对象结构,但我很好奇是否有一种明显的Pythonic方法来处理这个问题,或者我们是否必须去嵌套函数的JS路由调用实际创建新变量?

>>> l = []
>>> for r in range(10):
...     l.append((lambda x: lambda: x)(r))
...
>>> for f in l:
...     f()
...
0
1
2
# etc

1 个答案:

答案 0 :(得分:24)

一种方法是使用具有默认值的参数:

l = []
for r in range(10):
    def foo(r = r):
        return r
    l.append(foo)

for f in l:
    print(f())

产量

0
1
2
3
4
5
6
7
8
9

这是有效的,因为它在r的本地范围内定义foo,并在定义foo时将默认值绑定到它。


另一种方法是使用函数工厂:

l = []
for r in range(10):
    def make_foo(r):
        def foo():
            return r
        return foo
    l.append(make_foo(r))

for f in l:
    print(f())

这是有效的,因为它在r的本地范围内定义make_foo,并在调用make_foo(r)时为其绑定值。稍后,当调用f()时,使用LEGB rule查找r。虽然在r的本地范围内找不到foo,但它可以在make_foo的封闭范围内找到。