Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
74 views
in Technique[技术] by (71.8m points)

python - Why is the command bound to a Button or event executed when declared?

My code is:

from Tkinter import *

admin = Tk()
def button(an):
    print an
    print 'het'

b = Button(admin, text='as', command=button('hey'))
b.pack()
mainloop()

The button doesn't work, it prints 'hey' and 'het' once without my command, and then, when I press the button nothing happens.

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Consider this code:

b = Button(admin, text='as', command=button('hey'))

It does exactly the same as this:

result = button('hey')
b = button(admin, text='as', command=result)

Likewise, if you create a binding like this:

listbox.bind("<<ListboxSelect>>", some_function())

... it's the same as this:

result = some_function()
listbox.bind("<<ListboxSelect>>", result)

The command option takes a reference to a function, which is a fancy way of saying you need to pass it the name of the function. To pass a reference you must use the name only, without using parenthesis or arguments. For example:

b = Button(... command = button)

If you want to pass a parameter such as "hey" you must use a little extra code:

  • You can create an intermediate function that can be called without your argument and which then calls your button function,
  • You can use lambda to create what is referred to as an anonymous function. In every way it's a function except it doesn't have a name. When you call the lambda command it returns a reference to the created function, which means it can be used for the value of the command option to the button.
  • You can use functools.partial

For me, lambda is the simplest since it doesn't require any additional imports like functools.partial does, though some people think that functools.partial is easier to understand.

To create a lambda function that calls your button function with an argument you would do something like this:

lambda: button('hey')

You end up with a function that is functionally equivalent to:

def some_name():
    return button('hey')

As I said earlier, lambda returns a reference to this nameless function. Since a reference is what the command option expects you can use lambda directly in the creation of the button:

b = Button(... command = lambda: button('hey'))

There's a question on this site that has a lot of interesting comments about lambda, in general. See the question Why Python lambdas are useful?. That same discussion has an answer that shows how to use lambdas in a loop when you need to pass in a variable to the callback.

Finally, see the section titled Tkinter Callbacks on effbot.org for a nice tutorial. The coverage of lambda is pretty lean but the information there might still be useful.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...