Python Lambda在循环中
考虑下面的代码片段:
# directorys == {'login': <object at ...>, 'home': <object at ...>}
for d in directorys:
self.command["cd " + d] = (lambda : self.root.change_directory(d))
我期望创建一个两个函数的字典,如下所示:
# Expected :
self.command == {
"cd login": lambda: self.root.change_directory("login"),
"cd home": lambda: self.root.change_directory("home")
}
但它看起来像生成的两个lambda函数完全相同:
# Result :
self.command == {
"cd login": lambda: self.root.change_directory("login"),
"cd home": lambda: self.root.change_directory("login") # <- Why login ?
}
我真的不明白为什么。 你有什么建议吗 ?
您需要为每个创建的函数绑定d。 一种方法是将其作为参数传递给默认值:
lambda d=d: self.root.change_directory(d)
现在函数内部的d使用该参数,即使它具有相同的名称,并且在创建该函数时评估该参数的默认值。 为了帮助你看到这一点:
lambda bound_d=d: self.root.change_directory(bound_d)
记住默认值是如何工作的,比如像列表和字典这样的可变对象,因为你绑定了一个对象。
具有默认值的参数的这种习惯用法已经足够普通,但如果您反思函数参数并根据它们的存在确定该做什么,则可能会失败。 您可以通过另一次关闭来避免该参数:
(lambda d=d: lambda: self.root.change_directory(d))()
# or
(lambda d: lambda: self.root.change_directory(d))(d)
更好的是,重新设计你如何处理“命令”将有助于在这里,并应该在别处帮助。
这是由于d被绑定的点。 lambda函数都指向变量d
而不是它的当前值,所以当您在下一次迭代中更新d
时,可以在所有函数中看到此更新。
举一个更简单的例子:
funcs = []
for x in [1,2,3]:
funcs.append(lambda: x)
for f in funcs:
print f()
# output:
3
3
3
你可以通过添加一个附加函数来解决这个问题,例如:
def makeFunc(x):
return lambda: x
funcs = []
for x in [1,2,3]:
funcs.append(makeFunc(x))
for f in funcs:
print f()
# output:
1
2
3
您还可以修复lambda表达式内的范围
lambda bound_x=x: bound_x
但是,一般来说,这并不是一个好习惯,因为您已经更改了函数的签名。
我遇到了同样的问题。 选定的解决方案对我有很大帮助,但我认为有必要添加一个精度来使问题的代码具有功能性:在循环外部定义lambda函数。 顺便说一下,默认值是没有必要的。
foo = lambda d: lambda : self.root.change_directory(d)
for d in directorys:
self.command["cd " + d] = (foo(d))
链接地址: http://www.djcxy.com/p/28609.html