我有一些代码分布在多个文件中,试图从彼此导入,如下所示:

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和物理。py -但我如何解决这个问题?


参见在Python中使用相互导入或循环(循环)导入时会发生什么?了解WRT循环导入所允许的内容以及导致问题的原因。参见为什么循环导入看起来在调用堆栈中更上一层,但随后在更下一层引发ImportError ?有关问题发生的原因和方式的技术细节。


当前回答

问题很明显:实体和物理模块中名称之间的循环依赖关系。

无论导入整个模块还是仅仅导入一个类,都必须加载名称。

看这个例子:

# a.py
import b
def foo():
  pass
b.bar()
# b.py
import a
def bar():
  pass
a.foo()

这将被汇编成:

# a.py
# import b
# b.py
# import a # ignored, already importing
def bar():
  pass
a.foo()
# name a.foo is not defined!!!
# import b done!
def foo():
  pass
b.bar()
# done!

只要做一点小小的改变,我们就能解决这个问题:

# a.py
def foo():
  pass
import b
b.bar()
# b.py
def bar():
  pass
import a
a.foo()

这将被汇编成:

# a.py
def foo():
  pass
# import b
# b.py
def bar():
  pass
# import a # ignored, already importing
a.foo()
# import b done!
b.bar()
# done!

其他回答

我也得到了这个错误,因为一个不同的原因…

from my_sub_module import my_function

主脚本有Windows行结束符。my_sub_module有UNIX行结束符。将它们更改为相同的就解决了这个问题。它们还需要具有相同的字符编码。

问题很明显:实体和物理模块中名称之间的循环依赖关系。

无论导入整个模块还是仅仅导入一个类,都必须加载名称。

看这个例子:

# a.py
import b
def foo():
  pass
b.bar()
# b.py
import a
def bar():
  pass
a.foo()

这将被汇编成:

# a.py
# import b
# b.py
# import a # ignored, already importing
def bar():
  pass
a.foo()
# name a.foo is not defined!!!
# import b done!
def foo():
  pass
b.bar()
# done!

只要做一点小小的改变,我们就能解决这个问题:

# a.py
def foo():
  pass
import b
b.bar()
# b.py
def bar():
  pass
import a
a.foo()

这将被汇编成:

# a.py
def foo():
  pass
# import b
# b.py
def bar():
  pass
# import a # ignored, already importing
a.foo()
# import b done!
b.bar()
# done!

不是专门针对这个请求器的,但是如果导入的类名与导入的文件中的定义不匹配,同样的错误会显示出来。

也不是直接相关的OP,但重启PyCharm Python控制台失败后,添加一个新对象到一个模块,也是一个很好的方式,得到一个非常混乱的ImportError:不能导入名称…

令人困惑的是,PyCharm会在控制台中自动完成导入,但导入随后会失败。

虽然你绝对应该避免循环依赖,但你可以在python中延迟导入。

例如:

import SomeModule

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

这(至少在某些情况下)将避免错误。