tkinter creating buttons in for loop passing command arguments

I am trying to create buttons in tkinter within a for loop. And with each loop pass the i count value out as an argument in the command value. So when the function is called from the command value I can tell which button was pressed and act accordingly. The problem is, lets say len is 3, it will create 3 buttons with titles "Game 1" through "Game 3" but when any of the buttons are pressed the printed value is always 2, the last iteration. So it appears the buttons are being made as separate entities, but the i value in the command arguments seem to be all the same. Here is the code:

def createGameURLs(self):
    self.button = []
    for i in range(3):
        self.button.append(Button(self, text='Game '+str(i+1),command=lambda:self.open_this(i)))
        self.button[i].grid(column=4, row=i+1, sticky=W)
def open_this(self, myNum):
    print(myNum)

Is there a way to get the current i value, upon each iteration, to stick with that particular button?


Change your lambda to lambda i=i: self.open_this(i).

This may look magical, but here's what's happening. When you use that lambda to define your function, the open_this call doesn't get the value of the variable i at the time you define the function. Instead, it makes a closure, which is sort of like a note to itself saying "I should look for what the value of the variable i is at the time that I am called". Of course, the function is called after the loop is over, so at that time i will always be equal to the last value from the loop.

Using the i=i trick causes your function to store the current value of i at the time your lambda is defined, instead of waiting to look up the value of i later.


This is how closures work in python. I ran into this problem myself once. You could use functools.partial for this.

for i in range(3):
    self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i)))