I'm trying to create 6 buttons in a for loop using tkinter, each button's command points at the same function, but passes a variable (the loop counter.. in this case i) now for some reason.. when i run it, and click on each button, the function is supposed to print the variable passed to it from the button, so i'd expect:

click button 1 -> prints 1 to screen
click button 2 -> prints 2 to screen

However i end up with:
click button 1 - > prints 6 to screen
click button 2 - > prints 6 to screen again..
click button 3 - > 6 yet again.
etc.. etc

the code i'm using follows:

def buttonClick(button_number):
    print button_number

if __name__ == '__main__':
    root = Tk()
    for i in range(1,6):
        Button(root, text="%i"%(i), command=lambda:buttonClick(i)).grid(row=i, column=2)

It seems to be displaying the last value of 'i'?

thanks in advance

aah, found out why.

the lambda function needs to be passed the value for 'i' rather than just taking it from the for loop,
instead of:

lambda: buttonClick(i)

it should be:

lambda btn=i: buttonClick(btn)


Instead of lambda you can also use Python's partial function, new in Python25. Here is a simple example ...

# a tiny Tkinter calculator showing the
# use of the new Python25 partial function

import Tkinter as tk
from functools import partial  # needs Python25 or higher

def click(key):
    global memory
    if key == '=':
        # avoid division by integer
        if '/' in entry.get() and '.' not in entry.get():
            entry.insert(tk.END, ".0")
        # guard against the bad guys abusing eval()
        str1 = "-+0123456789."
        if entry.get()[0] not in str1:
            entry.insert(tk.END, "first char not in " + str1)
        # here comes the calculation part
            result = eval(entry.get())
            entry.insert(tk.END, " = " + str(result))
            entry.insert(tk.END, "--> Error!")
    elif key == 'C':
        entry.delete(0, tk.END)  # clear entry
    elif key == '->M':
        memory = entry.get()
        # extract the result
        if '=' in memory:
            ix = memory.find('=')
            memory = memory[ix+2:]
        root.title('M=' + memory)
    elif key == 'M->':
        entry.insert(tk.END, memory)
    elif key == 'neg':
        if '=' in entry.get():
            entry.delete(0, tk.END)
            if entry.get()[0] == '-':
                entry.insert(0, '-')
        except IndexError:
        # previous calculation has been done, clear entry
        if '=' in entry.get():
            entry.delete(0, tk.END)
        entry.insert(tk.END, key)

root = tk.Tk()
root.title("My Calculator PF")

# this also shows the calculator's button layout
btn_list = [
'7',  '8',  '9',  '*',  'C',
'4',  '5',  '6',  '/',  'M->',
'1',  '2',  '3',  '-',  '->M',
'0',  '.',  '=',  '+',  'neg' ]

# create all buttons with a loop
r = 1
c = 0
for b in btn_list:
    rel = 'ridge'
    cmd = partial(click, b)  # <-------
    c += 1
    if c > 4:
        c = 0
        r += 1

# use Entry widget for an editable display
entry = tk.Entry(root, width=33, bg="yellow")
entry.grid(row=0, column=0, columnspan=5)


ah that looks interesting, i'll have a look.


p.s that is an incredibly small calculator, great coding tips in it, thanks.

This question has already been answered. Start a new discussion instead.