2012-08-03 53 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