我正在用tkinter编写一个GUI应用程序,现在我想使用tkinter内置的消息框,所以我想,因为我已经导入了tkinter(如tk),它只是tk.messagebox.showerror()
但是这个或多或少的工作...
我通过IDLE运行时没有任何问题,但是如果我在终端中使用python <module-name>.py
则抛出一个AttributeError。
这是我能做的最简单的样本:
import tkinter as tk
root = tk.Tk()
tk.messagebox.showerror(title="Test Error", message="This is a test")
root.mainloop()
现在,如果我添加from tkinter import messagebox
作为导入,那么事情就会变得更加奇怪了,当从终端运行时(保持tk.messagebox.showerror
),这个代码同样有效。显然,它仍然必须被视为tkinter的一个属性,那么为什么没有显式导入它不能工作呢?
我想我并不是真的在寻找解决方案(因为我找到了一些方法让它发挥作用),但更多地解释了为什么会发生这种情况。
一如既往,欢迎任何建议!
答案 0 :(得分:1)
此问题之前出现过“为什么import tkinter; tkinter.font
在IDLE中有效但在python中无效?”解释是import
如何工作以及IDLE当前如何设置执行代码的子进程之间的交互。
IMPORT:sys.modules是一个将模块名称映射到导入的模块对象的字典。在高级别,import modname
等同于以下内容。
if modname not in sys.modules:
sys.modules[modname] = module(modname)
modname = sys.modules[modname]
对于python编码的包,该模块是从modname/__init__.py
创建的。导入包不会导入其子模块。也就是说,它不会运行modname/submodule.py
。随后导入子模块将子模块添加到sys.modules并作为属性添加到包中。之后导入模块将现有模块(具有子模块作为属性)绑定到指定的名称。
IDLE:当IDLE设置运行代码的子进程时,它直接或间接地导入tkinter及其子模块。 (代码在idlelib / run.py和它导入的idlelib模块中。)这可以通过运行来看到
for name in sys.modules:
if name.startswith('tkinter'):
print(name)
当IDLE启动时因此,当您运行import tkinter
时,它是进程中的第二个tkinter导入,名称'tkinter'
绑定到将子模块作为属性的现有tkinter模块
解决方案:IDLE的一个目的是开发在python本身运行的代码。 IDLE运行错误的代码是一个错误,无法在python中运行。我正在研究refactoring idlelib,以便上述内容不会打印任何内容。唯一需要的tkinter模块是tkinter.messagebox,只有在出现阻止运行代码的问题时才需要。因此导入messagebox
可能会被延迟,直到需要为止,这很少。