如何在没有全局关键字的情况下使用 tkinter 中的按钮更改全局变量?

How to change a global variable without global keyword using a button in tkinter?

我正在制作剪刀石头布程序,我需要更改当他们单击按钮时轮到谁,但我不想使用 global 关键字,因为该程序在函数内部。

这是我在不使用 global 关键字的情况下尝试执行的操作的示例:

from tkinter import *
root = Tk()

var = 1

def buttonClick():
    global var
    var += 1
    print(var)

button = Button(root, text="button", command=buttonClick).pack()
root.mainloop()

我试过写 command=(var += 1) 但没有成功。

如果整个脚本在一个函数中(包括 buttonClick() 函数)则使用 nonlocal 关键字:

def buttonClick():
    nonlocal var
    var += 1
    print(var)

如果函数没有嵌套,唯一的方法是在两个函数中创建一个全局变量和global关键字。

不,你确实不能。例如,如果它是一个列表,则可以更改全局 varcontents。然后您可以将命令编写为没有完整函数体的 lambda 表达式。

但这根本不是最好的设计。

Tkinter 事件模型与 Python 对象模型结合得很好——在某种程度上,您可以包含class 中与 UI 相关的所有内容 - 即使它只有一个实例 - 这样你的程序就可以以“self.var”的形式访问 var,以“self.button_click 的形式访问命令]”,如果他们不应该把事情搞砸的危险很小。

只是您找到的大多数文档和教程都会有继承 tkinter 对象本身并在现有 classes 之上添加您的元素的 OOP 示例。我强烈反对这种方法:tkinter classes 已经足够复杂了,有数百个方法和属性——即使是一个复杂的程序也只需要几十个内部状态让你担心。

最好的事情是联系:您想要访问的所有内容都应该成为您 class 的成员。在程序的开始,您实例化 class,这将创建 UI 元素并保留对它们的引用:

import tkinter as tk # avoid wildcard imports: it is hard to track what is available on the global namespace

class App:
    def __init__(self):
        self.root = tk.Tk()
        self.var = 1
        # keep a refernce to the button (not actually needed, but you might)
        self.button = tk.Button(self.root, text="button", command=self.buttonClick)
        self.button.pack()

    def buttonClick(self):
        # the button command is bound to a class instance, so
        # we get "self" as the object which has the "var" we want to change
        self.var += 1
        print(self.var)

    def run(self):
        self.root.mainloop()


if __name__ == "__main__": # <- guard condition which allows claases and functions defined here to be imported by larger programs
    app = App()
    app.run()

是的,你可以。这里有一个 hacky 的方式来说明它 可以 完成,尽管它肯定不是做这些事情的推荐方式。 免责声明:我的想法来自an answer to a related question

from tkinter import *

root = Tk()
var = 1
button = Button(root, text="button",
                command=lambda: (globals().update(var=var+1), print(var)))
button.pack()
root.mainloop()