16

I'm new to Python and trying to write a program with tkinter. Why is the Hello-function below executed? As I understand it, the callback would only be executed when the button is pressed? I am very confused...

>>> def Hello():
        print("Hi there!")

>>> hi=Button(frame,text="Hello",command=Hello())
Hi there!
>>> 
nbro
  • 15,395
  • 32
  • 113
  • 196
wjakobw
  • 525
  • 1
  • 4
  • 11

2 Answers2

37

It is called while the parameters for Button are being assigned:

command=Hello()

If you want to pass the function (not it's returned value) you should instead:

command=Hello

in general function_name is a function object, function_name() is whatever the function returns. See if this helps further:

>>> def func():
...     return 'hello'
... 
>>> type(func)
<type 'function'>
>>> type(func())
<type 'str'>

If you want to pass arguments, you can use a lambda expression to construct a parameterless callable.

>>> hi=Button(frame, text="Hello", command=lambda: Goodnight("Moon"))

Simply put, because Goodnight("Moon") is in a lambda, it won't execute right away, instead waiting until the button is clicked.

Kevin
  • 74,910
  • 12
  • 133
  • 166
mac
  • 42,153
  • 26
  • 121
  • 131
  • Thank you! Obvious follow-up is; how do I pass arguments? I am now reading about Lambda, it seems that might just be the answer. – wjakobw Nov 25 '11 at 12:33
  • @wjakobw - Pass argument to the function or pass the function as argument? In the first case you declare arguments in the function definition ex: `def func(par1, par2):` in the latter, you simply use the function name without parenthesis, as I outlined in my answer. Since you are admittedly new to python, may I suggest [this reading](http://www.diveintopython.net/)? It's easy to follow and very enjoyable. – mac Nov 25 '11 at 12:36
  • 1
    I would want to pass a variable as argument when the button is pressed. The usual way command=Hello(arg) won't work as the callback then contains parantheses and uses the return-value instead of the function. *In above example Hello-function takes no arguments, but imagine some other case. – wjakobw Nov 25 '11 at 12:51
  • @wjakobw - One of the regular patterns used in python is to pass a list of objects in which the first is the function, and the others its parameters (see the way subprocesses are called in the [`subprocess`](http://docs.python.org/library/subprocess.html) module, for example). If this is not an option, what you probably want is using [closures](http://en.wikipedia.org/wiki/Closure_(computer_science)). A nice article about their implementation in python is [this one](http://ynniv.com/blog/2007/08/closures-in-python.html). – mac Nov 25 '11 at 12:57
3

You can also use a lambda expression as the command argument:

import tkinter as tk
def hello():
    print("Hi there!")

main = tk.Tk()
hi = tk.Button(main,text="Hello",command=lambda: hello()).pack()
main.mainloop()
jjm
  • 49
  • 1
  • 5
    Lambda is completely unnecessary if you aren't passing arguments. You could improve your answer by showing how to use lambda to pass arguments. – Bryan Oakley Nov 29 '13 at 17:05