0

我正在Menu使用 Tkinter 在 Python 3.7 中创建一个。当我创建具有硬编码值的菜单时,例如:

obj_menu = Menu(textbox, tearoff=0)
obj_menu.add_command(label="a", command=lambda : foo("a", index))
index = index + 1
obj_menu.add_command(label="b", command=lambda : foo("b", index))

一切正常。在我的回调方法foo()中,分别选择第一个和第二个菜单项时,我得到了正确的 a 和 b 值。

但是当我在 for 循环中创建这个菜单时,我总是在我的回调方法 foo() 中得到最后一个字符。

for idx, char in enumerate(alphabets):
    obj_menu.add_command(label=char, command=lambda : foo(char, idx))

我很困惑为什么无论我选择哪个菜单索引,该方法都只能获取最后一个索引的值。我错过了什么吗?

4

3 回答 3

1

如果你确实想创建一个函数列表,而不是使用lambda你可以使用库中的 Pythonpartial()函数functools。例如:

for idx, char in enumerate(alphabets):
    obj_menu.add_command(label=char, command=partial(foo, char, idx))

下面在一个小测试示例中显示了两种不同方法的结果:

from functools import partial

def foo(char, idx):
    print(char, idx)
    return idx

alphabets = "abc"

print("Using lambda")
funcs = []

for idx, char in enumerate(alphabets):
    funcs.append([char, lambda : foo(char, idx)])

for char, func in funcs:
    print(char, func())

print("\nUsing partial")
funcs = []

for idx, char in enumerate(alphabets):
    funcs.append([char, partial(foo, char, idx)])

for char, func in funcs:
    print(char, func())

这将显示以下输出:

Using lambda
a 2
a 2
b 2
b 2
c 2
c 2

Using partial
a 0
a 0
b 1
b 1
c 2
c 2

可以看出,第一种方法失败了,导致最后一个lambda变体被用于所有调用,而partial()函数正常工作。

于 2019-07-15T06:40:22.117 回答
0

当您创建该形式的 lambda 表达式时,您实际上是在做类似这样的事情:

index = [whatever value]
def _implicit_func():
    return foo("a", index)
obj_menu.add_command(label="a", command=_implicit_func)

我希望你能看到这个index变量在函数作用域之外也是可用的。这意味着您可以编辑此变量,它将改变该函数的所有未来执行。

如果您仍然感到困惑,这里是Python 变量范围的参考。

于 2019-07-15T06:20:49.740 回答
0

解决方案是在 lambda 中创建临时变量并在方法调用中使用它们。

for idx, char in enumerate(alphabets):
obj_menu.add_command(label=char, command=lambda c=char, i=idx : foo(c, i))

感谢这个答案:https ://stackoverflow.com/a/17677768/970422

于 2019-07-15T07:22:37.940 回答