【问题标题】:How to change a global variable without global keyword using a button in tkinter?如何使用 tkinter 中的按钮更改没有全局关键字的全局变量?
【发布时间】:2022-03-03 02:42:53
【问题描述】:

我正在制作一个剪刀石头布程序,我需要更改当他们单击按钮时轮到谁,但我不想使用 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),但没有成功。

【问题讨论】:

标签: python python-3.x tkinter


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    不,你确实不能。例如,如果它是一个列表,则可以更改全局 var内容。然后你可以把你的命令写成一个没有完整函数体的 lambda 表达式。

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

    Tkinter 事件模型与 Python 对象模型很好地结合在一起——在某种程度上,你可以在一个类中包含所有与 UI 相关的东西,而不是仅仅将你的 UI 组件放在顶层(所有全局的),由稀疏函数协调。将永远只有一个实例 - 这样您的程序可以将 var 作为“self.var”访问,将命令作为“self.button_click”访问,而不会出现任何不应该发生的事情的危险。

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

    最好的事情是关联:您想要访问的所有内容都应该是您班级的成员。在您的程序开始时,您实例化您的类,这将创建 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()
    
    

    【讨论】:

    • 你说你不能改变它,但你肯定可以使用nonlocal关键字吗?除非我误解了这个问题。我确实认为您的方法总体上更好
    • FWIW,在tkinter 应用程序中,将全局变量设为IntVar 将允许通过使用其set() 方法对其进行更改(无需事先声明global)。
    【解决方案3】:

    是的,你可以。这是一种 hacky 方法,说明它可以完成,尽管它肯定不是做这些事情的推荐方法。 免责声明:我从an answerrelated 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()
    

    【讨论】:

    • 但这肯定不会因为同样的原因global 不起作用?- 所有代码都在一个函数中
    • @Lecdi:如果变量是全局的,因为它目前在 OP 问题的 code 中(他们说这是“我正在尝试的一个例子”)做”)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多