tkinter 消息框的子导入问题

Sub import issues with tkinter messagebox

我正在用 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 的一个属性,那么为什么没有显式导入它就不能工作?

我想我并不是真的在寻找这样的解决方案(因为我找到了使它起作用的方法),而是更多地解释了为什么会发生这种情况。

一如既往地欢迎任何建议!

这个问题之前以 "Why does import tkinter; tkinter.font works in IDLE but not in python itself?" 的形式出现过,解释是 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 为 运行ning 代码设置子进程时,它会直接或间接导入 tkinter 及其子模块。 (代码在idlelib/run.py和它导入的idlelib模块中。)这个可以通过运行ning

看到
for name in sys.modules:
    if name.startswith('tkinter'):
        print(name)

空闲开始时。所以,当你 运行 import tkinter 时,它是进程中的第二个 tkinter 导入,名称 'tkinter' 绑定到现有的 tkinter 模块,该模块具有子模块作为属性

解决方案:IDLE 的一个目的是开发 运行 在 python 本身中的代码。这是 IDLE 的一个错误 运行 错误代码,不会 运行 在 python 中。我正在研究 refactoring idlelib 以便上面不会打印任何内容。唯一需要的 tkinter 模块是 tkinter.messagebox 并且只有在出现阻止 运行ning 代码的问题时才需要。所以导入messagebox可以延迟到需要的时候,这种情况很少见。