Lym*_*urd 4 python lambda list-comprehension python-2.7
这个问题是从涉及Tkinter按钮的回调函数的原始应用程序中提炼出来的.这是说明行为的一行.
lambdas = [lambda: i for i in range(3)]
如果你然后尝试调用生成的lambda函数:
lambdas[0](),lambdas[1]()并且lambdas[2]()都返回2.
期望的行为是lambdas[0]()返回0,lambdas[1]()返回1,lambdas[2])()返回2.
我看到索引变量是通过引用解释的.问题是如何改写以使其按价值处理.
使用参数使用默认值的绑定电流值的i局部变量.在lambda没有参数i的情况下调用gets 时,会为局部变量分配默认值:
In [110]: lambdas = [lambda i=i: i for i in range(3)]
In [111]: for lam in lambdas:
.....: print(lam())
.....:
0
1
2
Run Code Online (Sandbox Code Playgroud)
如果i不是局部变量,Python会在封闭范围内查找其值.找到的值i是列表推导的for循环中获得的最后一个值.这就是为什么在没有带默认值的参数的情况下,每个都lambda返回2,因为在调用lambdas时for循环已经完成.
解决此问题的另一种常见方法是使用闭包 - 一种可以引用不再活动的环境的函数, 例如外部函数的本地命名空间,即使在该函数返回之后也是如此.
def make_func(i):
return lambda: i
lambdas = [make_func(i) for i in range(3)]
for lam in lambdas:
print(lam())
Run Code Online (Sandbox Code Playgroud)
版画
0
1
2
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为在lam()调用
函数时,由于函数体i中的lambda函数不是局部变量,因此Python会i在函数的封闭范围内查找值make_func.lam即使make_func已经完成,它的本地命名空间仍然可以被闭包访问.该本地命名空间中的值是传递给的值
make_func,幸运的是,它是期望的值i.
正如mkrieger1已经提到的,使用已经提供的一些参数值创建新函数的另一种方法是使用functools.partial:
lambdas = [functools.partial(lambda x: x, i) for i in range(3)]
Run Code Online (Sandbox Code Playgroud)
您可以functools.partial通过部分应用从更通用的函数创建专用函数,这会将参数计数减少一:
from functools import partial
lambdas = [partial(lambda x: x, i) for i in range(3)]
Run Code Online (Sandbox Code Playgroud)
此处,lambda x: x是采用一个参数的通用恒等函数,您可以创建它的三种特化,不采用参数并返回固定值。