Python Lambda在一个循环中

考虑下面的代码片段:

# directorys == {'login': <object at ...>, 'home': <object at ...>} for d in directorys: self.command["cd " + d] = (lambda : self.root.change_directory(d)) 

我期望创build一个两个函数的字典如下:

 # 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 ? } 

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

您需要为每个创build的函数绑定d。 一种方法是将其作为parameter passing给默认值:

 lambda d=d: self.root.change_directory(d) 

现在,函数内部的d使用参数,尽pipe它具有相同的名称,并且在创build函数时评估其默认值。 为了帮助你看到这个:

 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) 

更好的是,重新devise你如何处理“命令”将有助于在这里,并应该在别处帮助。

这是由于d被绑定的点。 lambda函数都指向variables 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 

您也可以修复lambdaexpression式内的范围

 lambda bound_x=x: bound_x 

但是一般来说,这是不好的做法,因为你已经改变了你的函数的签名。

我遇到了同样的问题。 选定的解决scheme帮了我很多,但我认为有必要添加一个精度来使问题的代码function:在循环之外定义lambda函数。 顺便说一下,默认值是没有必要的。

 foo = lambda d: lambda : self.root.change_directory(d) for d in directorys: self.command["cd " + d] = (foo(d))