给出这段代码:
funcs = []
for x in range(3):
funcs.append(lambda: x)
print [f() for f in funcs]
我希望它能打印[0, 1, 2]
,而是打印[2, 2, 2]
。关于lambdas如何使用范围,我是否缺少一些基本的东西?
答案 0 :(得分:8)
这是Python中的一个常见问题。基本上,范围是这样的:当调用f()
时,它将使用x
的当前值,而不是lambda形成时x
的值。有一个标准的解决方法:
funcs = []
for x in range(10):
funcs.append(lambda x=x: x)
print [f() for f in funcs]
使用lambda x = x
检索并保存x
的当前值。
答案 1 :(得分:5)
x绑定到模块级x(从for循环中遗留下来)。
更清楚一点:
funcs = []
for x in range(10):
funcs.append(lambda: x)
x = 'Foo'
print [f() for f in funcs]
# Prints ['Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo']
答案 2 :(得分:4)
你知道答案:是的。 ;)然而,请放心,因为这是崭露头角的pythonistas的一个非常普遍的发现。当您定义一个引用该函数内未“创建”的变量的函数或lambda时,它会在变量上创建一个闭包。结果是,在调用函数时获取变量的值,而不是定义时的值。 (你期待后者。)
有几种方法可以解决这个问题。首先是绑定额外的变量:
funcs = []
for x in range(10):
funcs.append(lambda x=x: x)
print [f() for f in funcs]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
第二种方式更为正式:
from functools import partial
funcs = []
for x in range(10):
funcs.append(partial(lambda x: x, x))
print [f() for f in funcs]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]