Python 通配符导入 vs 命名导入
好的,我在我的一个项目中遇到了一些奇怪的情况,希望有人能告诉我原因。我的文件结构是这样的:
MainApp.py
res/
__init__.py
elements/
__init__.py
MainFrame.py
在 MainFrame.py 文件里,我定义了一个叫做 RPMWindow 的类,它是从 wx.Frame 这个类扩展出来的。
在 MainApp.py 文件中,这样做是可以的:
from res.elements.MainFrame import *
但这样做就不行:
from res.elements.MainFrame import RPMWindow
我知道使用通配符导入不会造成什么问题,但我更想搞明白为什么命名导入会失败,而通配符导入却成功。
当我使用类名时,出现了这个错误信息:
Traceback (most recent call last):
File "C:\myApps\eclipse\plugins\org.python.pydev.debug_1.5.6.2010033101\pysrc\pydevd.py", line 953, in <module>
debugger.run(setup['file'], None, None)
File "C:\myApps\eclipse\plugins\org.python.pydev.debug_1.5.6.2010033101\pysrc\pydevd.py", line 780, in run
execfile(file, globals, locals) #execute the script
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\MainApp.py", line 2, in <module>
from res.elements.MainFrame import RPMWindow
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\res\elements\MainFrame.py", line 2, in <module>
from res.elements.MenuBar import MenuBarBuilder
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\res\elements\MenuBar.py", line 2, in <module>
from MainApp import _, DataCache
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\MainApp.py", line 2, in <module>
from res.elements.MainFrame import RPMWindow
ImportError: cannot import name RPMWindow
而当我使用通配符导入时,我没有收到错误信息,应用程序可以正常打开。
3 个回答
你的代码中出现了循环导入的问题:一个模块既需要另一个模块,又被另一个模块所需要,这样的情况其实很危险。大部分问题可以通过使用 import a
的方式来解决,之后用 a.b
来引用,而不是用 from a import b
或 from a import *
。
特别要注意的是,绝对不要使用 from a import *
。这种通配符导入会让你的命名空间变得杂乱无章,使得代码更难维护、阅读、理解和预测。import a
和 from a import *
的区别,就像是把一个箱子拖进房间和把箱子里的东西洒得到处都是。
如果能把共享的代码移到一个单独的模块中,或者以其他方式重构代码,避免循环导入,那会更好。循环导入总是表明设计上存在问题。
我没时间去研究你为什么通配符能用,但我可以告诉你,你直接导入名字失败的原因是你的代码里有一个导入循环:
你试图导入 res.elements.MainFrame
,但是那部分代码又试图导入 res.elements.MenuBar
,而 res.elements.MenuBar
又想导入 res.elements.MainFrame
。换句话说,你第一次导入 res.elements.MainFrame
还没完成,就又试图导入一次了。
你遇到了循环导入的问题:
MainFrame.py 文件间接地在导入 MainApp.py,而 MainApp.py 又在导入 MainFrame.py。这样一来,当 MainApp.py 尝试导入 MainFrame.py 的时候,RPMWindow 这个类还没有被定义,所以你就会看到 ImportError(导入错误)。