为什么我的 Button 的命令在我创建 Button 时立即执行,而不是在我单击它时执行?

新手上路,请多包涵

我的代码是:

 from Tkinter import *

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

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

该按钮不起作用,它在没有我命令的情况下打印一次“嘿”和“het”,然后,当我按下按钮时,什么也没有发生。

原文由 salk 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 312
1 个回答

考虑这段代码:

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

它的作用与此完全相同:

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

同样,如果您创建这样的绑定:

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

…与此相同:

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

command 选项引用了一个函数,这是一种奇特的方式,表示您需要将函数名称传递给它。要传递引用,您必须仅使用名称,而不能使用括号或参数。例如:

 b = Button(... command = button)

如果你想传递一个参数,比如“hey”,你必须使用一些额外的代码:

  • 您可以创建一个可以在没有参数的情况下调用的中间函数,然后调用您的 button 函数,
  • 您可以使用 lambda 创建所谓的 _匿名函数_。在任何方面它都是一个函数,除了它没有名字。当您调用 lambda 命令时,它会返回对创建的函数的 _引用_,这意味着它可用于按钮的 command 选项的值。
  • 您可以使用 functools.partial

对我来说, lambda 是最简单的,因为它不需要像 functools.partial 这样的任何额外导入,尽管有些人认为 functools.partial 更容易理解-

要创建一个 lambda 函数来调用你的 button 带有参数的函数,你可以这样做:

 lambda: button('hey')

您最终得到的函数在功能上等同于:

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

正如我之前所说, lambda 返回对这个无名函数的引用。由于参考是 command 选项,您可以直接在按钮的创建中使用 lambda

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

总的来说,这个网站上有一个问题有很多关于 lambda 的有趣评论。请参阅问题 为什么 Python lambda 有用? .同样的讨论有 一个答案,展示了当您需要将变量传递给回调时如何在循环中使用 lambda

最后,请参阅标题为 Tkinter 回调zone.effbot.org 文章以获得不错的教程。 lambda 的覆盖范围非常小,但那里的信息可能仍然有用。

原文由 Bryan Oakley 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题