0

I've written a simple calculator code in Python using Tkinter. Almost every function works but I can't seem to figure out what the lambda function does in my project. If I add it works without any bug but if I remove it shows an error.

Here is the block where the error points out

class Calc:
    def __init__(self):
        self.total = 0
        self.current = ''
        self.ip_val = True
        self.check_sum = False
        self.op = ''
        self.result = False

    def operation(self, op):
        self.current = float(self.current) #this line generates error
        if self.check_sum:
            self.valid_function()
        elif not self.result:
            self.total = self.current
            self.ip_val = True
        self.check_sum = True
        self.op = op
        self.result = False

Here's the line calling the CALC class's operation method.

Button(calc, text='x^y', width=6, height=2, font=('arial', 20, 'bold'), bd=4, bg="gray20",
       command= res.operation('pow')).grid(row=1, column=5, pady=1)

ERROR MESSAGE

Traceback (most recent call last):
  File "T:/WorkSpace/PythonCourse/Day-6.py", line 235, in <module>
    command= res.operation('pow')).grid(row=1, column=5, pady=1)
  File "T:/WorkSpace/PythonCourse/Day-6.py", line 69, in operation
    self.current = float(self.current)
ValueError: could not convert string to float: ''

FYI, I know IF I initialize the Button class like below ( with lambda function )

Button(calc, text='x^y', width=6, height=2, font=('arial', 20, 'bold'), bd=4, bg="gray20",
       command= lambda: res.operation('pow')).grid(row=1, column=5, pady=1)

IT WORKS JUST FINE.

QUERY

I want an explanation of how this lambda function is the solution to this error. And also if the user doesn't press the button, the function shouldn't call itself. How's this even compiling?

Sifat Amin
  • 1,091
  • 6
  • 15
  • lambda is sort of like a function definition and when You define a function You can also call another function in that definiton. and the function inside the definition will be called only after the defined function is called, so when You add `()` at the end of the function You are calling it and lambda is the definition that that doesn't allow an immediate call – Matiiss Apr 14 '21 at 10:20
  • 2
    Do you know that `command=res.operation('pow')` will execute `res.operation('pow')` immediately, not when the button is clicked? – acw1668 Apr 14 '21 at 10:21
  • Well, how did you know that there is such a thing as lambda? What happened when you went back to that source of information and checked its explanation? Also, what happened when you tried putting `python what is a lambda` into a search engine? Explaining what the fundamental concepts mean and how they work, is off topic for Stack Overflow. You should try to look in existing tutorials and documentation, and if you are still confused then try an *actual discussion forum* such as Reddit or Quora. – Karl Knechtel Apr 14 '21 at 10:22
  • What is it you don't understand, exactly? `command` expects a callable (i.e a function). When you don't use a lambda expression, you pass the result of `res.operation('pow')` instead of passing a callable (a function). `res.operation('pow')` always returns `None`, but the program never gets to that point, and instead, it errors on this line `self.current = float(self.current)` because `self.current` is an empty string. – juanpa.arrivillaga Apr 14 '21 at 10:26
  • " And also if the user doesn't press the button, the function shouldn't call itself. How's this even compiling?" what? *You* are calling the function, when you use `command= res.operation('pow')`. – juanpa.arrivillaga Apr 14 '21 at 10:27
  • [Please read this](https://stackoverflow.com/questions/16501/what-is-a-lambda-function/62742314#62742314) – Thingamabobs Apr 14 '21 at 14:26
  • Thank you @Matiiss for clearing my confusion – Sifat Amin Apr 14 '21 at 16:20

1 Answers1

0

Consider this line of code:

Button(..., command= res.operation('pow'))

It will behave exactly the same as these two lines of code:

result = res.operation('pow')
Button(..., command= result)

This is simply how python works. It's not unique to tkinter. When python sees x(y), it executes x immediately under most circumstances.

See the problem? res.operation('pop') immediately calls the function when you create the button, not when you click the button. When defining a button, you need to set the command attribute to a callable.

There are several ways to tell tkinter what function to call. If you didn't have any arguments you would just give it the name of the function itself:

Button(..., command=res.operation)

However, in this case, you need to pass an argument so you can't just pass the function name to the command. You need to pass both the name and the argument. This is where lambda comes in. lambda creates a new function, and passes that function to the command parameter.

In effect, Button(..., ,command=lambda res.opeeration('pow')) is roughly the same as this:

def i_dont_care_what_the_name_is():
    res.operation('pow')
Button(..., command=i_dont_care_what_the_name_is)

Note, it's not exactly the same, but the differences are unimportant in this discussion.

Bottom line is that lambda gives an easy way to pass a callable to a function or to assign it to an attribute or variable.

For the record, another way to get the same result is to use functools.partial. Some people prefer that over lambda, though using lambda doesn't require an extra import the way functools.partial does.

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