循环中的 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 ?
}

我真的不明白为什么。你有什么建议吗 ?

原文由 FunkySayu 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 600
2 个回答

您需要为每个创建的函数绑定 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)

原文由 Roger Pate 发布,翻译遵循 CC BY-SA 4.0 许可协议

这是由于 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

但是总的来说,这 不是 好的做法,因为您已经更改了函数的签名。

原文由 robbie_c 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题