2013-03-08 32 views
2

我想用Tkinter製作一個計算器。我一直在努力清理代碼,但遇到了一些麻煩。當創建按鈕,我使用以下代碼:lambda與tkinter奇怪地工作

Button(self,text="1",command=lambda: self.addkey("1"),width=self.defaultwidth,height=self.defaultheight).grid(row=5, column=0) 
Button(self,text="2",command=lambda: self.addkey("2"),width=self.defaultwidth,height=self.defaultheight).grid(row=5, column=1) 
Button(self,text="3",command=lambda: self.addkey("3"),width=self.defaultwidth,height=self.defaultheight).grid(row=5, column=2) 

用下面是所述命令時按鈕1,2和3按該順序被壓稱爲

def addkey(self,key): 
      # Adds a given key to the display 
      if len(self.displaytext) + len(key) <= self.maxlength: 
       self.displaytext += key 
       self.display["text"] = self.displaytext 

,以下是輸出:

123 

我一直在試圖清理代碼,以便它看起來更像是:

for i in range(3): 
    Button(self,text=str(i+1),command=lambda: self.addkey(str(i+1)),width=self.defaultwidth,height=self.defaultheight).grid(row=5, column=i) 

這增加的按鈕,但是當1,2和3的順序按下,下面顯示在屏幕上:

333 

我在想,如果我錯過了什麼或者這根本就是不可能。

+0

你能發表更多的代碼嗎?我假設這個按鈕創建代碼是從類的'__init __()'方法運行的? – pydsigner 2013-03-08 23:39:20

+0

我認爲這是一個經典的Python詞法範圍gotcha – slezica 2013-03-08 23:44:37

回答

5

啊,範圍界定。當你這樣做:

command=lambda: self.addkey(str(i)) 

「解決」的i多項在那裏,然後。你只是告訴lambda在被調用時引用i,之後

在任何時候過去for循環,i = 3(最終值)的結束,因此所有的lambda表達式得到3當他們問i

如果我沒有弄錯,你可以添加一個函數作爲間接手段,它會適當地從周圍的範圍「捕獲」i

def add_key_f(i): 
    return lambda self: self.addkey(i) 
+3

這個問題的經典解決方法(除了你提到的那個問題)是添加一個關鍵字arg:'command = lambda i = i:self.addkey(str(i)) ' – user4815162342 2013-03-08 23:46:34

+4

另一種選擇:'command = functools.partial(self.addkey,str(i))'。 – Dougal 2013-03-08 23:49:09

+0

有趣!我從來沒有見過任何一種方法!默認參數很髒,但是哦_so聰明! – slezica 2013-03-08 23:50:13