如何解决“ImportError: Cannot import name X”或“AttributeError: ...(可能由于循环导入)”?
我有一些代码分散在多个文件中,它们之间尝试相互导入
,具体如下:
main.py:
from entity import Ent
entity.py:
from physics import Physics
class Ent:
...
physics.py:
from entity import Ent
class Physics:
...
然后我从main.py
运行这些代码,结果出现了以下错误:
Traceback (most recent call last):
File "main.py", line 2, in <module>
from entity import Ent
File ".../entity.py", line 5, in <module>
from physics import Physics
File ".../physics.py", line 2, in <module>
from entity import Ent
ImportError: cannot import name Ent
我猜这个错误是因为在main.py
中导入了entity
一次,而在physics.py
中又导入了一次——那么我该如何解决这个问题呢?
另外,您可以查看 在Python中使用互相或循环导入时会发生什么?,了解哪些是允许的,哪些会导致循环导入的问题。还可以查看 为什么循环导入在调用栈的上层似乎可以工作,但在下层却引发ImportError?,获取关于问题发生的原因和方式的技术细节。
16 个回答
这是一个循环依赖的问题。这个问题可以在不改变代码结构的情况下解决。问题的出现是因为在vector
中,你要求entity
立即可用,而entity
又反过来要求vector
可用。造成这个问题的原因是你在模块准备好之前就想访问它的内容——通过使用from x import y
。这实际上就像是
import x
y = x.y
del x
Python能够检测到循环依赖,并防止无限导入的循环。基本上,发生的事情是为模块创建了一个空的占位符(也就是说,它没有内容)。一旦循环依赖的模块被编译,它就会更新被导入的模块。这个过程大致是这样的。
a = module() # import a
# rest of module
a.update_contents(real_a)
为了让Python能够处理循环依赖,你必须只使用import x
的方式。
import x
class cls:
def __init__(self):
self.y = x.y
因为你不再在顶层引用模块的内容,所以Python可以在不实际访问循环依赖内容的情况下编译模块。这里的顶层是指在编译时会被执行的代码行,而不是函数内部的内容(例如y = x.y
)。静态变量或类变量访问模块内容也会导致问题。
虽然你应该尽量避免循环依赖,但在Python中你可以延迟导入模块。
比如说:
import SomeModule
def someFunction(arg):
from some.dependency import DependentClass
这样做(至少在某些情况下)可以绕过这个错误。
你遇到了循环依赖的问题。也就是说,physics.py
在 entity
还没有定义类 Ent
之前就被引入了,而 physics
又试图引入已经在初始化中的 entity
。你需要把 entity
模块中对 physics
的依赖去掉。