当前位置: 代码迷 >> 综合 >> python cyclic import(循环导入)的小分析
  详细解决方案

python cyclic import(循环导入)的小分析

热度:92   发布时间:2023-12-14 21:22:11.0

踩了一个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

  相关解决方案