这个问题是从涉及 Tkinter 按钮回调函数的原始应用程序中提炼出来的。这是说明该行为的一行。
lambdas = [lambda: i for i in range(3)]
如果您随后尝试调用生成的 lambda 函数:lambdas[0]()
, lambdas[1]()
and lambdas[2]()
全部返回2。
期望的行为是lambdas[0]()
返回0,lambdas[1]()
返回1,lambdas[2])()
返回 2.
我看到索引变量是通过引用解释的。问题是如何重新表述以按价值对待它。
使用具有默认值的参数来绑定当前值 of i
到局部变量。当。。。的时候lambda
被调用时不带参数,局部变量i
被赋予默认值:
In [110]: lambdas = [lambda i=i: i for i in range(3)]
In [111]: for lam in lambdas:
.....: print(lam())
.....:
0
1
2
When i
不是局部变量,Python在封闭范围内查找其值。找到的值是最后一个值i
在列表理解的 for 循环中获得。这就是为什么,如果没有默认值的参数,每个lambda
返回 2,因为在调用 lambda 时 for 循环已完成。
解决这个问题的另一种常见方法是使用闭包——可以引用不再活动的环境的函数 例如外部函数的本地命名空间,即使该函数返回后也是如此.
def make_func(i):
return lambda: i
lambdas = [make_func(i) for i in range(3)]
for lam in lambdas:
print(lam())
prints
0
1
2
这是有效的,因为当lam()
被调用,因为i
in the lambda
函数体不是局部变量,Python 查找的值i
在
函数的封闭范围make_func
。它的本地命名空间仍然是
可接近封闭,lam
, 虽然make_func
已经
完全的。该本地命名空间中的值是传递给的值make_func
,幸运的是,这是期望的值i
.
As mkrieger1 已经提到过,
使用已提供的一些参数值创建新函数的另一种方法
是使用functools.partial:
lambdas = [functools.partial(lambda x: x, i) for i in range(3)]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)