Lambda 循环[重复]
- 2024-11-22 08:47:00
- admin 原创
- 211
问题描述:
考虑以下代码片段:
# 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 ?
}
我真的不明白为什么。你有什么建议吗?
解决方案 1:
您需要为每个创建的函数绑定 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)
解决方案 2:
这是由于 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
然而一般来说这不是一个好的做法,因为您已经改变了函数的签名。
解决方案 3:
lambda
或者,你可以使用,而不是functools.partial
,在我看来,它的语法更清晰。
而不是:
for d in directorys:
self.command["cd " + d] = (lambda d=d: self.root.change_directory(d))
这将是:
for d in directorys:
self.command["cd " + d] = partial(self.root.change_directory, d)
或者,这是另一个简单的例子:
numbers = [1, 2, 3]
lambdas = [lambda: print(number)
for number in numbers]
lambdas_with_binding = [lambda number=number: print(number)
for number in numbers]
partials = [partial(print, number)
for number in numbers]
for function in lambdas:
function()
# 3 3 3
for function in lambdas_with_binding:
function()
# 1 2 3
for function in partials:
function()
# 1 2 3
解决方案 4:
我遇到了同样的问题。所选的解决方案对我有很大帮助,但我认为有必要增加精度以使问题的代码具有功能性:在循环之外定义 lambda 函数。顺便说一句,默认值不是必需的。
foo = lambda d: lambda : self.root.change_directory(d)
for d in directorys:
self.command["cd " + d] = (foo(d))
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD