Reputation: 484
I am trying to make a calculator using Tkinter. I have been trying to clean up the code a bit but have run into a snag. When creating buttons, I use the following code:
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)
With the following being the command called
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
When buttons 1, 2, and 3 are pressed in that order, the following is the output:
123
I have been trying to clean up the code so that it looks more like:
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)
This adds the buttons fine, but when 1, 2, and 3 are pressed in that order, the following shows up on the screen:
333
I was wondering if I missed something or this is simply not possible.
Upvotes: 2
Views: 186
Reputation: 76949
Ah, scoping. When you do this:
command=lambda: self.addkey(str(i))
You're not "resolving" the i
to a number right there and then. You're just telling the lambda to reference i
when it's invoked, afterwards.
At any time past the end of the for
loop, i = 3
(last value), so all of your lambdas get 3
when they ask for i
.
If I'm not mistaken, you can add a function as means of indirection, and it will appropriately "capture" i
from the surrounding scope.
def add_key_f(i):
return lambda self: self.addkey(i)
Upvotes: 5