如何解决“ImportError: Cannot import name X”或“AttributeError: ...(可能由于循环导入)”?

753 投票
16 回答
1119425 浏览
提问于 2025-04-17 12:54

我有一些代码分散在多个文件中,它们之间尝试相互导入,具体如下:

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 个回答

139

这是一个循环依赖的问题。这个问题可以在不改变代码结构的情况下解决。问题的出现是因为在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)。静态变量或类变量访问模块内容也会导致问题。

181

虽然你应该尽量避免循环依赖,但在Python中你可以延迟导入模块。

比如说:

import SomeModule

def someFunction(arg):
    from some.dependency import DependentClass

这样做(至少在某些情况下)可以绕过这个错误。

615

你遇到了循环依赖的问题。也就是说,physics.pyentity 还没有定义类 Ent 之前就被引入了,而 physics 又试图引入已经在初始化中的 entity。你需要把 entity 模块中对 physics 的依赖去掉。

撰写回答