-1

I am working on a calculator using tkinter, but when using lambda for commands in a button, it produces incorrect results. When a button is pressed, the intended result was to have that button's number added and displayed to the entry, however when lambda is used, the maths is broken.

numbers = [1,2,3,4,5,6,7,8,9]

ent_calc = tk.Entry(bg="white",fg="black",font=("Calibri, 30"))
ent_calc.grid(row=0, columnspan=4, sticky="nsew", ipady=30)

def number(num):
ent_calc.insert(tk.END, str(num))

for i in range(3):
root.rowconfigure(i+1, weight=1, minsize=12)
for j in range(3):
    root.columnconfigure(j, weight=1, minsize=50)
    if i == 0:
        btn = tk.Button(text=numbers[j], width=10, height = 5, command=lambda: number(i+j+1))
        btn.grid(row=i+1,column=j, padx=5, pady=5, sticky="nsew")
    elif i == 1:
        btn = tk.Button(text=numbers[j+3], width=10, height = 5, command=lambda: number(i+j+3))
        btn.grid(row=i+1,column=j, padx=5, pady=5, sticky="nsew")
    elif i == 2:
        btn = tk.Button(text=numbers[j+6], width=10, height = 5, command=lambda: number(i+j+5))
        btn.grid(row=i+1, column=j, padx=5, pady=5, sticky="nsew")

Instead of each button displaying the correct numbers on the entry when pressed, the 1,2,3 buttons display 6, the 4,5,6 buttons display 8, and the 7,8,9 buttons display 10.

When each button from 1-9 is pressed once, this happens:

On the other hand, I've managed to make the code work as intended by using partial from the functools module. Why does lambda give unintended results?

  • 4
    Lambda uses late binding closures. See this question for more details: https://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture, and also this article https://docs.python-guide.org/writing/gotchas/#late-binding-closures – Luka Mesaric May 19 '20 at 11:46

1 Answers1

1

You have to account for i and j changing their values! What you could do is copy the variables to local variables and use the copies:

numbers = [1,2,3,4,5,6,7,8,9]

ent_calc = tk.Entry(bg="white",fg="black",font=("Calibri, 30"))
ent_calc.grid(row=0, columnspan=4, sticky="nsew", ipady=30)

def number(num):
  ent_calc.insert(tk.END, str(num))

  for i in range(3):
    root.rowconfigure(i+1, weight=1, minsize=12)
    localI = i
    for j in range(3):
      localJ = j
      root.columnconfigure(j, weight=1, minsize=50)
      if i == 0:
        btn = tk.Button(text=numbers[j], width=10, height = 5, command=lambda: number(localI+localJ+1))
        btn.grid(row=i+1,column=j, padx=5, pady=5, sticky="nsew")
      elif i == 1:
        btn = tk.Button(text=numbers[j+3], width=10, height = 5, command=lambda: number(localI+localJ+3))
        btn.grid(row=i+1,column=j, padx=5, pady=5, sticky="nsew")
      elif i == 2:
        btn = tk.Button(text=numbers[j+6], width=10, height = 5, command=lambda: number(localI+localJ+5))
        btn.grid(row=i+1, column=j, padx=5, pady=5, sticky="nsew")

Luca Schimweg
  • 747
  • 5
  • 18