在Python中,当两个模块试图相互导入时会发生什么?更一般地说,如果多个模块试图在一个循环中导入会发生什么?
另见我能做什么关于“ImportError:不能导入名称X”或“AttributeError:…”(很可能是由于循环导入)”?关于可能导致的常见问题,以及如何重写代码以避免此类导入的建议。参见为什么循环导入看起来在调用堆栈中更上一层,但随后在更下一层引发ImportError ?有关问题发生的原因和方式的技术细节。
在Python中,当两个模块试图相互导入时会发生什么?更一般地说,如果多个模块试图在一个循环中导入会发生什么?
另见我能做什么关于“ImportError:不能导入名称X”或“AttributeError:…”(很可能是由于循环导入)”?关于可能导致的常见问题,以及如何重写代码以避免此类导入的建议。参见为什么循环导入看起来在调用堆栈中更上一层,但随后在更下一层引发ImportError ?有关问题发生的原因和方式的技术细节。
当前回答
模块a.py:
import b
print("This is from module a")
模块b.py
import a
print("This is from module b")
运行“Module a”将输出:
>>>
'This is from module a'
'This is from module b'
'This is from module a'
>>>
它输出了这3行,而由于循环导入,它应该输出不定式。 这里列出了运行“模块a”时逐行发生的事情:
The first line is import b. so it will visit module b The first line at module b is import a. so it will visit module a The first line at module a is import b but note that this line won't be executed again anymore, because every file in python execute an import line just for once, it does not matter where or when it is executed. so it will pass to the next line and print "This is from module a". After finish visiting whole module a from module b, we are still at module b. so the next line will print "This is from module b" Module b lines are executed completely. so we will go back to module a where we started module b. import b line have been executed already and won't be executed again. the next line will print "This is from module a" and program will be finished.
其他回答
模块a.py:
import b
print("This is from module a")
模块b.py
import a
print("This is from module b")
运行“Module a”将输出:
>>>
'This is from module a'
'This is from module b'
'This is from module a'
>>>
它输出了这3行,而由于循环导入,它应该输出不定式。 这里列出了运行“模块a”时逐行发生的事情:
The first line is import b. so it will visit module b The first line at module b is import a. so it will visit module a The first line at module a is import b but note that this line won't be executed again anymore, because every file in python execute an import line just for once, it does not matter where or when it is executed. so it will pass to the next line and print "This is from module a". After finish visiting whole module a from module b, we are still at module b. so the next line will print "This is from module b" Module b lines are executed completely. so we will go back to module a where we started module b. import b line have been executed already and won't be executed again. the next line will print "This is from module a" and program will be finished.
循环导入会终止,但在模块初始化期间,您需要注意不要使用循环导入的模块。
考虑以下文件:
a.py:
print "a in"
import sys
print "b imported: %s" % ("b" in sys.modules, )
import b
print "a out"
b.py:
print "b in"
import a
print "b out"
x = 3
如果你执行a.py,你会得到以下结果:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out
在第二次导入b.py时(在第二个ain中),Python解释器不会再次导入b,因为它已经存在于模块dict中。
如果你试图在模块初始化期间从a访问b.x,你会得到一个AttributeError。
将下面的行追加到a.py:
print b.x
则输出为:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
Traceback (most recent call last):
File "a.py", line 4, in <module>
import b
File "/home/shlomme/tmp/x/b.py", line 2, in <module>
import a
File "/home/shlomme/tmp/x/a.py", line 7, in <module>
print b.x
AttributeError: 'module' object has no attribute 'x'
这是因为模块是在导入时执行的,在访问b.x时,x = 3行还没有执行,这只会在b退出后发生。
我完全同意pythoneer的回答。但是我偶然发现了一些代码,它们在循环导入时存在缺陷,并在尝试添加单元测试时引起了问题。因此,为了快速修补它而不改变一切,你可以通过动态导入来解决这个问题。
# Hack to import something without circular import issue
def load_module(name):
"""Load module using imp.find_module"""
names = name.split(".")
path = None
for name in names:
f, path, info = imp.find_module(name, path)
path = [path]
return imp.load_module(name, f, path[0], info)
constants = load_module("app.constants")
同样,这不是一个永久性的修复,但可以帮助那些希望在不修改太多代码的情况下修复导入错误的人。
干杯!
假设您正在运行一个名为request.py的测试python文件 在request.py中,您写入
import request
所以这也很可能是一个循环导入。
解决方案:
只需将测试文件更改为另一个名称,例如aaa.py,而不是request.py。
不要使用其他库已经使用过的名称。
bar.py
print('going to import foo')
from foo import printx
foo.py
print('trying to import bar')
import bar
def printx():
print('x')
$ python bar.py
going to import foo
trying to import bar
going to import foo
Traceback (most recent call last):
File "bar.py", line 2, in <module>
from foo import printx
File "/home/suhail/Desktop/temp/circularimport/foo.py", line 2, in <module>
import bar
File "/home/suhail/Desktop/temp/circularimport/bar.py", line 2, in <module>
from foo import printx
ImportError: cannot import name 'printx' from partially initialized module 'foo' (most likely due to a circular import) (/home/suhail/Desktop/temp/circularimport/foo.py)