使用Lambda函数在Tkinter右键单击中的分配问题

时间:2019-01-16 22:51:30

标签: python tkinter lambda right-click

我有一个非常复杂的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循环不起作用。知道为什么吗?

1 个答案:

答案 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()))

这里有一些链接: