如何解决Python - 全局变量和类方法
好的,所以我差点失去我的弹珠。
我正在开发一个小应用程序,它从输入的 XML 文件中获取问题,将它们显示在屏幕上,获取答案并将其写回输出 XML,使用 tkinter 进行 GUI 和 ElementTree 进行 XML 处理。 每个问题可能有多个检查和子问题,它们会根据需要动态显示在各自的框架上。
主窗口由 main
创建为 MainWindow
类实例(其中包含所有 tkinter 的东西和一堆有用的方法),在代码的最后:
def main():
global app
window = Tk()
app = MainWindow(window)
window.mainloop()
if __name__ == '__main__':
main()
这应该使“应用程序”成为一个全局变量,可以从代码的任何位置访问,对吗?
.....显然不是?
我创建了 Question 类,它存储从 XML 中提取的属性,处理文本的显示,并为 XML 中的每个元素创建一个 Check 类,并为 XML 中的每个元素创建一个 Subquestion 类。
>问题类如下:
class Question:
def __init__(self,element):
self.element = element
self.question_text = element.get('text')
self.ok = element.get('ok')
self.answer = element.get('r')
self.comment = element.get('comment')
if element.find('check') is None:
#print(app)
pass
else:
#print(app)
for check in element.iter('check'):
Check(check)
for subq in element.iter('subquest'):
SubQuestion(subq)
还有 Check 类,它处理复选框的创建以及将它们各自的答案写入 ElementTree:
class Check:
def __init__(self,element):
self.element = element
self.check_text = element.get('text')
self.answer = element.get('r')
self.var = IntVar()
self.create_check()
def create_check(self):
print('check created')
print(app)
Checkbutton(app.frameChk,text=self.check_text,variable=self.var,command=self.write_check).pack(side=LEFT)
def write_check(self):
self.element.set('r',self.var.get())
print('check written')
到目前为止,一切都很好。它按预期工作,复选框出现并提交它们的值,没有问题
但是...在创建复选框时,您是否注意到 Check 类引用 create_check
中的 app.frameChk
方法?这是为复选框保留的 Tk 框架,由 MainWindow 的 __init__
方法创建。此 create_check
方法访问 app
没有任何问题,即使其中没有 global
关键字。我什至添加了 print(app)
只是为了确保。
果然,每次创建复选框时,它都会将 <__main__.MainWindow object at 0x0000024CCC557BE0>"
打印到控制台。
但是...在 Question 的 __init__
方法(或其他任何地方,就此而言),我似乎无法访问与 app
相关的任何内容,它抛出 classes_app.py",line 129,in __init__ - print(app) NameError: name 'app' is not defined
>
到底是为什么?这两个类不从其他类继承任何东西,并且在层次上“相等”,只是程序中的两个普通类(实际上,Question 是创建 Check 实例的类!)。一个人认识全球而其他人不认识?
最令人难以置信的是:Check
类中没有 global
关键字,它仍然有效吗?
到目前为止我已经尝试过:
1 - 在全局范围内的 app = MainWindow(window)
函数之外声明 main
。没什么。
2 - 在程序的每个函数中使用 global
关键字,看看他们是否得到它。没有。
3 - 将 main
函数放在代码的最顶部,所以这将是第一个
app
的声明,似乎也没什么用。
4 - 上述解决方案和反复试验的恶作剧的任意组合。
5 - 为 python globals 的代码女神牺牲一块主板。
请注意,我对 python 还很陌生,所以我可能已经理解了一些关于全局变量的可怕错误,或者完全没有理解它,但是从文档的说法来看,使用 global
关键字声明的变量应该是一个全局变量,并且全局变量可以从代码中的任何和所有函数和方法访问,对吗?
如果你问我为什么如此需要 app = MainWindow(window)
是全局的:将有一个全局函数来清理每个问题之间的小部件:
def destroy_widgets(parent):
for widget in parent.winfo_children():
widget.destroy()
例如,在类的方法中,我将其称为 destroy_widgets(app.frameChk)
。这是我第一次遇到问题的方式。
我会发布整个代码,但所有这些 tkinter 定义都非常广泛。如果你们认为有必要,我当然会。
任何帮助或见解将不胜感激,非常感谢,这个社区是黄金!
解决方法
变量的定义/生命周期
关于这一点:
最令人难以置信的是:Check 类中没有 global 关键字,它仍然有效吗?
您只需要 global
关键字来在本地上下文中创建或更改全局变量,see this answer。
此外,语句 global app
尚未创建变量 app
- 它仅在第一次赋值时创建。在您的示例中,这意味着 app
仅在此处创建:app = MainWindow(window)
。
如果 Question
在此语句之前创建(在您的示例中,由 Tk()
或由 MainWindow(window)
),则 app
尚不存在。
你可以在解释器中试试这个:
>>> global app
>>> print(app)
Traceback (most recent call last):
File "<stdin>",line 1,in <module>
NameError: name 'app' is not defined
命名空间
另一个需要注意的重要事实:如果您的代码组织在不同的模块中,您必须注意命名空间。
示例
假设我们有两个 python 文件:first.py
和 second.py
:
first.py
的内容:
app = 5
second.py
的内容:
import first
print(first.app)
运行此工程:
$ python3 second.py
5
因为不同的模块,仅仅输入 print(app)
是行不通的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。