【问题标题】:Tkinter OptionMenu add a command to multiple OptionMenusTkinter OptionMenu 将命令添加到多个 OptionMenus
【发布时间】:2012-08-03 18:14:16
【问题描述】:

基本上我有一系列循环创建的 OptionMenus,但目前是空的:

option_menu = []
for ii in range(jj):
    option_menu.append([])  
    for ll in range(kk):   
        option_menu[ii].append(OptionMenu(frame,tkinter_text_var[ii][ll],''))

然后我在其他地方使用复选框来设置值:

for ii in range(jj):
    for ll in range(kk):   
        option_menu[ii][ll]["menu"].add_command(label = name_from_box.get(), command = lambda: tkinter_text_var[ii][ll].set(name_from_box.get()))

这可以正确填充所有 OptionMenus,但是当我在任何 OptionMenus 中选择一个值时,它只会设置 option_menu[jj][kk](即最后一个)。

那我做错了什么?

【问题讨论】:

    标签: python lambda tkinter closures optionmenu


    【解决方案1】:

    这是一个涉及闭包的非常常见问题。看下面的例子:

    alist = [lambda : x for x in range(10) ]
    print (alist[2]()) #9
    print (alist[4]()) #9
    

    都会是 9 岁。为什么?因为每个 lambda 函数都引用了变量xx 在循环的每次迭代中都会发生变化,但它们仍然引用同一个对象

    解决此问题的一种方法是使用默认参数。默认参数在创建函数时计算,而不是在调用时计算。

    alist = [lambda y=x: y for x in range(10) ]
    print (alist[2]()) #2
    print (alist[4]()) #4
    

    (做同样事情的另一种方法是functools.partial,你有时会看到...)

    我经常喜欢说——“小心闭包”。它们可能有点棘手。

    【讨论】:

    • 你说的是真的,但我认为答案会让不懂闭包或 lambda 的人感到困惑。
    • @BryanOakley -- 我认为任何人都很难掌握闭包的这一方面。我试图说明第一个示例中的 x 在所有 lambdas 之间共享,而在第二个示例中它不是。我不知道还能怎么说。如果您有任何建议让我更容易理解,我很乐意编辑(或者如果您发布更好的答案,请点赞 ;-)。
    • 应该提到,lambda 和 : 之间的内容类似于函数定义中括号中的内容。也就是说,绑定到仅对函数调用有效的变量。第一个代码块的问题在于,它只是假设在某处它可以看到一个 x,而且它当然“总是”是一样的。
    • 所以,对于一个愚蠢的理解,这类似于如果你这样做,说X = [1]Y = XX[0] = 9,那么Y[0]的值也将变为@987654331 @?
    • @DavidDuncan -- 是的,我想是的。在这种情况下,X[0]Y[0] 也引用同一个对象。
    猜你喜欢
    • 2012-07-09
    • 1970-01-01
    • 2021-06-28
    • 2017-08-17
    • 2018-09-02
    • 2023-04-06
    • 2020-12-28
    • 1970-01-01
    • 2022-07-14
    相关资源
    最近更新 更多