-1

So the thing is that in onw video the youtuber removed the lambda on the equal and Clear buttons of the calculator, but my code (that I basically copied from him) only works with the lambda (in his video his code did not work with lambda), so I want to understando why.... Ty (The video link https://www.youtube.com/watch?v=NzSCNjn4_RI)

The thing is in these lines:

btn_equals.grid(row=6, column=3, columnspan=2)
btn_clear = tk.Button(root, text='C', command=lambda: clear_field(), width=16, font=('Arial', 14))
btn_clear.grid(row=6, column=1, columnspan=2)
root.mainloop()

And here is the whole code (any suggestions on what would make it better would be appreciated (I am new to programming:

import tkinter as tk

calculation = ""


def add_to_calculation(symbol):
    global calculation
    calculation += str(symbol)
    text_result.delete(1.0, 'end')
    text_result.insert(1.0, calculation)


def evaluate_calculation():
    global calculation
    try:
        calculation = str(eval(calculation))
        text_result.delete(1.0, 'end')
        text_result.insert(1.0, calculation)
    except:
        clear_field()
        text_result.insert(1.0, "Erro")


def clear_field():
    global calculation
    calculation = ""
    text_result.delete(1.0, 'end')



root = tk.Tk()
root.geometry("380x450")

text_result = tk.Text(root, height=2.3, width=21, font=("Arial", 24))

text_result.grid(columnspan=5)

btn_1 = tk.Button(root, text='1', command=lambda: add_to_calculation(1), width=7, font=('Arial', 14))
btn_1.grid(row=2, column=1)
btn_2 = tk.Button(root, text='2', command=lambda: add_to_calculation(2), width=7, font=('Arial', 14))
btn_2.grid(row=2, column=2)
btn_3 = tk.Button(root, text='3', command=lambda: add_to_calculation(3), width=7, font=('Arial', 14))
btn_3.grid(row=2, column=3)
btn_4 = tk.Button(root, text='4', command=lambda: add_to_calculation(4), width=7, font=('Arial', 14))
btn_4.grid(row=3, column=1)
btn_5 = tk.Button(root, text='5', command=lambda: add_to_calculation(5), width=7, font=('Arial', 14))
btn_5.grid(row=3, column=2)
btn_6 = tk.Button(root, text='6', command=lambda: add_to_calculation(6), width=7, font=('Arial', 14))
btn_6.grid(row=3, column=3)
btn_7 = tk.Button(root, text='7', command=lambda: add_to_calculation(7), width=7, font=('Arial', 14))
btn_7.grid(row=4, column=1)
btn_8 = tk.Button(root, text='8', command=lambda: add_to_calculation(8), width=7, font=('Arial', 14))
btn_8.grid(row=4, column=2)
btn_9 = tk.Button(root, text="9", command=lambda: add_to_calculation(9), width=7, font=('Arial', 14))
btn_9.grid(row=4, column=3)
btn_0 = tk.Button(root, text='0', command=lambda: add_to_calculation(0), width=7, font=('Arial', 14))
btn_0.grid(row=5, column=1)

btn_plus = tk.Button(root, text="+", command=lambda: add_to_calculation("+"), width=7, font=('Arial', 14))
btn_plus.grid(row=2, column=4)
btn_minus = tk.Button(root, text='-', command=lambda: add_to_calculation("-"), width=7, font=('Arial', 14))
btn_minus.grid(row=3, column=4)
btn_mult = tk.Button(root, text='x', command=lambda: add_to_calculation("*"), width=7, font=('Arial', 14))
btn_mult.grid(row=4, column=4)
btn_div = tk.Button(root, text='/', command=lambda: add_to_calculation("/"), width=7, font=('Arial', 14))
btn_div.grid(row=5, column=4)

btn_open = tk.Button(root, text='(', command=lambda: add_to_calculation("("), width=7, font=('Arial', 14))
btn_open.grid(row=5, column=2)
btn_close = tk.Button(root, text=')', command=lambda: add_to_calculation(")"), width=7, font=('Arial', 14))
btn_close.grid(row=5, column=3)

btn_equals = tk.Button(root, text="=", command=lambda: evaluate_calculation(), width=16, font=('Arial', 14))
btn_equals.grid(row=6, column=3, columnspan=2)
btn_clear = tk.Button(root, text='C', command=lambda: clear_field(), width=16, font=('Arial', 14))
btn_clear.grid(row=6, column=1, columnspan=2)
root.mainloop()

I want to understand why the equal and clear buttons only works with the lambda in my code, but in the code of the youtuber it only works without the lambda. Thank you all

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • 1
    `command=lambda: evaluate_calculation()` does exactly the same thing as `command=evaluate_calculation`. You only need to use a `lambda` in cases where the function will need to receive a parameter (like your number buttons), since the Button will provide no parameters when it calls its `command=` function. – jasonharper Dec 06 '22 at 16:05
  • @jasonharper: *Technically* it could differ if `evaluate_calculation` was reassigned after the call using `command=` completed (the non-`lambda` would bind eagerly, seeing the value at bind time, the `lambda` would resolve lazily, at invocation time), but yeah, in general you're not reassigning/redefining functions, and `command=evaluate_calculation` is the more efficienct and simpler solution. All the ones without arguments could be handled with `functools.partial` though, skipping the `lambda`, e.g. `command=lambda: add_to_calculation(")")` becomes `command=partial(add_to_calculation, ")")`. – ShadowRanger Dec 06 '22 at 16:40

1 Answers1

0

The command attribute of a button requires a callable. That means it requires a reference to a function so that it can call the function once you click the button.

In practical terms, foo() calls the function foo, but foo without the parenthesis is a reference to the function. This reference is the callable -- something that can be called.

Let's get another bit of terminology out of the way. lambda is a way of creating an anonymous function - a function without a name. It returns the callable for the function.

For example, if I do x = lambda: print("hello!"), it has roughly the same effect as if I did:

def x():
    print("hello!")

In both cases (lambda and def) we can later do x() to call the function and have it print "hello!". lambda is convenient when creating buttons since the name is irrelevant, we just need to pass the callable to the button's command attribute.

Back to your example, you have a function named clear_field, and you want to call it when the button is clicked. The command attribute requires a callable so you can do this one of two ways.

The first way is to just directly reference the name of the function (without the ()). This tells the button "call the command clear_field when the user presses the button". When you click the button, tkinter will do clear_field() behind the scenes to call the function.

btn_clear = tk.Button(..., command=clear_field, ...)

The second way is to use lambda. In this case, just as if we were using def to create a new function, the body of the lambda needs to call other functions -- in this case, clear_field().

btn_clear = tk.Button(..., command=lambda: clear_field(), ...)

Both will work exactly the same.

So, why choose one over the other? Since a callable is a reference to a function, it can only be a reference to a function. It's not possible to pass arguments to the function. In the other buttons in your code, the command attribute uses lambda since it needs to pass an argument (1, 2, etc) to the function. Therefore it must use something that allows the function to be called with an argument. lambda is a good choice, though there are other alternatives. lambda is convenient because it doesn't require extra imports.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685