踩了一个python循环导入(英文貌似叫python cyclic import)的坑,小小地研究了一下,分享给大家:
首先明确几个逻辑:
1. import XXX的时候,实际上是解释器对XXX模块进行一次解析(执行),比如下面的代码会打印"B executed":
# a.py import b |
# b.py print("B executed") |
2. python在多次import同一个模块的时候,会将import的模块的信息(名称,路径)记录到sys.modules中,第二次import同一模块的时候,解释器会检查sys.modules里面是否已经有该模块了,如果有,不会再重新执行一次import。比如下面代码,执行a.py只会输出一次"B enter"和"B exit":
# a.py import b print("A enter") import b print("A exit") |
# b.py print("B enter") print("B exit") |
3. 在使用import XXX的时候,只要进入XXX模块,系统就会将XXX记录到sys.modules(此时可能XXX模块还没有完全解释完),例如下面的代码,执行a.py会得到"b module loaded : True",说明刚刚进入b.py,sys.modules中就已经有记录了:
# a.py import b |
# b.py import sys print("b module loaded : {}".format("b" in sys.modules)) …do other things… |
4. 在使用from XXX import YYY导入的时候,解释器仍然会对XXX进行完整的解释(但是如果在对XXX解释的过程中还没有解释到YYY就调用YYY的话,就会报错,具体见最后循环导入的例子),例如下面的示例,执行a.py的时候,仍然会等到"B exit"执行之后,才会打印"test":
# a.py from b import test test() |
# b.py print("B enter") def test(): print("test") print("B exit") |
基于上面的几个逻辑,对循环导入的一些问题做一个说明,来看两个不同的例子:
示例1:
# a.py print("A enter")
from b import test test() |
# b.py print("B enter")
def test(): print("test")
import a print("B exit") |
运行a.py的结果:
A enter
B enter
A enter
test
B exit
test
示例2:
# a.py print("A enter")
from b import test test() |
# b.py print("B enter")
import a
def test(): print("test")
print("B exit") |
运行a.py的结果:
A enter
B enter
A enter
Traceback (most recent call last):
File "a.py", line 3, in <module>
from b import test
File "b.py", line 4, in <module>
import a
File "a.py", line 3, in <module>
from b import test
ImportError: cannot import name 'test' from 'b' (b.py)
原因分析:
可以看到仅仅是因为import a的位置不通就产生了不同的运行结果。具体分析两个例子的不同:
示例1的解释过程:
进入__main__
print("A enter")
from b import test(解释器将b添加到sys.modules)
进入__b__
print("B enter")
解释def test()
import a(解释器将a添加到sys.modules)
print("A enter")
from b import test(此时b已经再sys.modules中,跳过)
执行test(),打印"test"
print("B exit")
执行test(),打印"test"
示例2的解释过程:
进入__main__
print("A enter")
from b import test(解释器将b添加到sys.modules)
进入__b__
print("B enter")
import a(解释器将a添加到sys.modules)
print("A enter")
from b import test(此时b已经再sys.modules中,跳过)
执行test(),此时解释器发现并b中并没有解释到test这个方法,于是报错
参考资料:
https://stackoverflow.com/questions/744373/circular-or-cyclic-imports-in-python
https://www.cnblogs.com/shengulong/p/10140225.html