解析python模块中的loop import

模块循环引用是大型开发中常遇到的问题,高级编程语言发展到今天仍有很多语言存在这类问题,目前也有一些年轻的语言考虑过这类问题(如在go的工程中,代码间存在模块循环引用会导致编译出错)。
很遗憾今天的主角:python工程中依然存在这类问题。接下来我将结合实例,详细解析模块循环引用出现的原因以及如何避免循环引用。
首先介绍示例工程结构:
– src
|-- loop1
| |-- a.py
| |-- b.py
|-- loop2
| |-- c.py
|-- mytest.py
模块之间的引用关系:mytest引用loop1包中的a模块,a模块引用loop2包中的c模块,c模块引用loop1中的b模块,b模块引用同级中的a模块
模块间的引用关系见下图:
解析python模块中的loop import_第1张图片

现象

模块内容:

# .mytest.py
from loop1.a import func_a

func_a()
#--------------------------
# ./loop1/a.py
from loop2.c import func_c

def func_a():
    print("use func a")
    func_c()
#--------------------------
# ./loop2/c.py
from loop1.b import func_b

def func_c():
    print("use func c")
    func_b()
#--------------------------
# ./loop1/b.py
from loop1.a import func_a

def func_b():
    print("use func b")
    func_a()

报错显示:

Traceback (most recent call last):
  File "mytest.py", line 1, in <module>
    from loop1.a import func_a
  File "/Users/lwb/PycharmProjects/llearn_python/loop1/a.py", line 1, in <module>
    from loop2.c import func_c
  File "/Users/lwb/PycharmProjects/llearn_python/loop2/c.py", line 1, in <module>
    from loop1.b import func_b
  File "/Users/lwb/PycharmProjects/llearn_python/loop1/b.py", line 1, in <module>
    from loop1.a import func_a
ImportError: cannot import name 'func_a'

分析

分析出错的原因前,我们需要搞清楚import语句的执行流程。在引用模块时,需要将模块所有的顶格代码都执行一遍,遇到函数和类的定义会作声明。
这一套引用流程本没有问题,但是在按行执行顶格代码时,如果碰到引用别的模块则会转到别的模块的定格代码,最终实现所有模块定格代码都执行为止。
如果出现模块的循环引用,这一美好的流程将会被打破。如样例工程,在mytest.py定格代码中先引用将执行从a模块中引用fu nc_a方法、a模块引用c模块func_c、c模块引用b模块func_b方法、最终b模块引用了a模块func_a方法;因为a模块定格代码未执行到func_a方法,所以会报不能引入func_a的错误。

解决方案

了解模块的引入和执行机制后,依据需求目前有3种解决方案:

  1. 使用延迟导入模块,即只在有需要的方法或类中引入,以模块a为例:
# ./loop1/a.py
def func_a():
    print("use func a")
    from loop2.c import func_c
    func_c()
  1. 直接引入模块名,使用时通过模块名调用方法,以模块a为例:
# ./loop1/a.py
import loop2.c

def func_a():
    print("use func a")
    loop2.c.func_c()
  1. 重新设计代码结构,选择将代码合并或分离(推荐方法
    在这里推荐业内通用的3层模型结构:如flask官方将模块拆分成utils(最基础模块)、(forms、models、errors)(上层基础模块)、views(顶层模块);上级和下级模块只能单向引用

参考

  1. https://www.jianshu.com/p/9c7c11cc5a92
  2. https://zhuanlan.zhihu.com/p/30832759
  3. https://www.zhihu.com/question/19887316

你可能感兴趣的:(python)