2012-08-03 50 views
1

基本上我有在一个循环创造了一系列OptionMenus的,但现在还是空的:的Python的Tkinter OptionMenu添加一个命令到多个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](即最后一个制)。

那么我做错了什么?

回答

4

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

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你会有时会看到...)

我经常喜欢说的 - “照顾与倒闭潮”。他们可能有点棘手。

+0

你说的是真的,但我认为答案会让不明白闭包或lambda的人感到困惑。 – 2012-08-03 18:58:12

+0

@BryanOakley--我认为封闭的这个方面对任何人都很难理解。我试图清楚地表明,第一个例子中的x在所有lambda中共享,而在第二个例子中则不是。我不知道该怎么说。如果您有任何建议让我更容易理解,我很乐意编辑(或者如果您发布了更好的答案,则为upvote ;-)。 – mgilson 2012-08-03 19:07:36

+0

应该提及的是,lambda和:之间的区别与函数定义中的括号相似。也就是说,它是绑定到只对此函数调用有效的变量。第一块代码的问题在于,它假设有一个它可以看到的地方,那当然会“永远”相同。 – LJNielsenDk 2012-08-04 09:03:46