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-在全局作用域中的main函数之外声明app = MainWindow(window)。没有什么

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 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.pysecond.py:

first.py:的内容

app = 5

second.py:的内容

import first
print(first.app)

运行此工作:

$ python3 second.py
5

由于模块不同,仅仅放置print(app)是不可行的。

相关内容

  • 没有找到相关文章

最新更新