我有一个非常复杂的Tkinter GUI,因此值得避免使用lambda函数重复进行工作分配控件。这里的代码摘录:
def createRightMenu(self, treeName, commands: []):
for cmd in commands:
self.rightMouse[treeName].add_command(label= cmd['label'], command= lambda: self.execCommand(cmd['reqId']))
self.tree[treeName].bind("<Button-3>", lambda event:
self.rightMouse_click(event.x_root, event.y_root, treeName))
def execCommand(self, reqId):
print("execCommand", reqId)
self.tree = {}
treeName = 'a'
self.createTree(root, treeName)
self.createRightMenu(treeName , [
{'label': 'copy', 'reqId': 1},
{'label': 'retrieve', 'reqId': 2},
])
什么工作? 在我的右键菜单中,获得条目“复制”和“检索”,并调用execCommand。
什么不起作用? 即使我右键单击``复制'',execCommand总是获取最后一个列表元素,即``检索'',2作为参数。如果我手动添加两个.add_command的全部就可以了。仅使用for循环不起作用。知道为什么吗?
答案 0 :(得分:1)
作用域问题:触发lambda
时,它将检查cmd
变量的范围。在for cmd in commands:
的每次迭代期间,cmd
变量被设置为新值。在迭代结束时,变量cmd
仍等于for cmd in commands:
的最终迭代(即-{'label': 'retrieve', 'reqId': 2}
)。
解决方案是在lambda
的签名中指定一个“ new”变量,然后使用它,因为python范围定义的工作方式(在“ new”上加引号,因为它可以是一样的名字)。具体来说,您可以将代码更改为:
for cmd in commands:
self.rightMouse[treeName].add_command(label= cmd['label'],
command= lambda reqid = cmd['reqId']: self.execCommand(reqid))
下面是一个脚本,通过示例演示了我在这里谈论的内容:
lambdas = []
words = ["Hello","World"]
print("Creating Lambds")
for word in words:
my_lambda = lambda: word
print('>>> Result for "{}" lambda: "{}"'.format(word,my_lambda()))
lambdas.append(my_lambda)
print("Post Loop Lambda Results")
for w,_lambda in zip(words,lambdas):
print('>>> Result for "{}" lambda: "{}"'.format(w,_lambda()))
word = "Foobar"
print('Setting word variable to "{}"'.format(word))
print("New Results for lambdas:")
for w,_lambda in zip(words,lambdas):
print('>>> Result for "{}" lambda: "{}"'.format(w,_lambda()))
print("----------------\nSolution:\n")
lambdas = []
words = ["Hello","World"]
print("Creating Lambds")
for word in words:
my_lambda = lambda myword = word: myword
print('>>> Result for "{}" lambda: "{}"'.format(word,my_lambda()))
lambdas.append(my_lambda)
print("Post Loop Lambda Results")
for w,_lambda in zip(words,lambdas):
print('>>> Result for "{}" lambda: "{}"'.format(w,_lambda()))
word = "Foobar"
print('Setting word variable to "{}"'.format(word))
print("New Results for lambdas:")
for w,_lambda in zip(words,lambdas):
print('>>> Result for "{}" lambda: "{}"'.format(w,_lambda()))
这里有一些链接: