0

I am working through a tutorial on tkinter. I adapted some code, with the idea that every time you clicked on the button we'd create a new text label in the row below. What is confusing me is that when I write command=click it works, but when I write command = click() the function is executed a single time at the beginning of the script but not when the button is pressed. The first behaves as I'd expect. The second behaviour confuses me, as I would expect it to raise an error not perform the function once without pressing the button.

from tkinter import *

root = Tk()


position = {"Loc":1}
def click(position=position):
    Label(root, text="ta").grid(row=position["Loc"], column=0)
    position["Loc"] = position["Loc"] + 1
    return

but = Button(root, text="click here to do nothing",command=click())
but.grid(row=0,column=0)



root.mainloop()

Note: I found the answer below more helpful than the answer to the related question here , because it made explicit that arguments are evaluated first before being passed into the function.

riemann_lebesgue
  • 299
  • 5
  • 17
  • 2
    Does this answer your question? [Why is the command bound to a Button or event executed when declared?](https://stackoverflow.com/questions/5767228/why-is-the-command-bound-to-a-button-or-event-executed-when-declared) – SAL Jul 30 '21 at 09:00
  • in part - but it doesn't seem to explain why something happens at all rather than an error. I.e., command expects to receive a reference to function, but actually is set equal to the return value of a function. – riemann_lebesgue Jul 30 '21 at 09:01
  • @ClownDown question now edited. The explanation that the argument variables are evaluated first (while in hindsight obvious) was not explicit in the other question – riemann_lebesgue Jul 30 '21 at 16:21

1 Answers1

4

When you run a function in Python (like but = Button(root, text="click here to do nothing",command=click())), first all of the arguments get evaluated and then passed to the function. So, you are calling click() and then assigning its return value to the command. If it returns None or something else that Button can handle you will get no error. When you pass just click, you actually tell the function that it is supposed to call that function whenever you click the button.

Some simple code to clarify the issue:

def foo(bar):
    print("\tCalling function {} from foo".format(bar))
    if bar:
        bar()

def fun():
    print("\tExecuting fun function")


print("\nPassing function")
foo(fun)

print("\nPassing function return value")
foo(fun())

If you check out the outputs you will notice that they get executed in different order - in the second case, fun is executed first, returns None and than that None value is given to foo as a bar argument.

Passing function
    Calling function <function fun at 0x000001A79F8863A0> from foo
    Executing fun function

Passing function return value
    Executing fun function
    Calling function None from foo

As to why there is no error - why would there be? Both are valid statements. You could have a function that returns other function and pass it to the button that way.

matszwecja
  • 6,357
  • 2
  • 10
  • 17