我有一些代码分布在多个文件中,试图从彼此导入,如下所示:
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 ?有关问题发生的原因和方式的技术细节。
这是一个循环依赖。不需要对代码进行任何结构修改就可以解决这个问题。出现这个问题是因为在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)。访问模块内容的静态变量或类变量也会导致问题。
逻辑清楚是很重要的。出现这个问题,是因为引用变成了死循环。
如果你不想改变逻辑,你可以把导致ImportError的import语句放到文件的另一个位置,例如末尾。
a.py
from test.b import b2
def a1():
print('a1')
b2()
b.py
from test.a import a1
def b1():
print('b1')
a1()
def b2():
print('b2')
if __name__ == '__main__':
b1()
导入错误:ImportError:不能导入名称'a1'
但是如果我们改变test的位置。b import b2 in A,如下所示:
a.py
def a1():
print('a1')
b2()
from test.b import b2
我们可以得到我们想要的:
b1
a1
b2
如果你从file1.py导入file1.py并使用这个:
if __name__ == '__main__':
# etc
file1.py中低于该值的变量不能导入到file1.py中,因为__name__不等于__main__!
如果你想从file1.py导入一些东西到file2.py,你需要在file1.py中使用这个:
if __name__ == 'file1':
# etc
如果有疑问,使用assert语句确定__name__=='__main__'
问题很明显:实体和物理模块中名称之间的循环依赖关系。
无论导入整个模块还是仅仅导入一个类,都必须加载名称。
看这个例子:
# 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!