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

上一篇: Python Lambda in a loop

下一篇: What is the scope of a defaulted parameter in Python?