关于Python如何避免循环导入问题详解


Posted in Python onSeptember 14, 2017

前言

Python 中使用package时,出现循环导入问题十分常见,我们创建如下package来说明这个问题:

pkg
 ├── __init__.py
 ├── module_a.py
 └── module_b.py

其中,

__init__.py 将pkg指定为一个Python package

module_a.py中定义了一个action_a()函数,该函数引用了module_b.py中的一个attribute,如一个函数或变量

module_b.py中定义了一个action_b()函数,该函数引用了module_a.py中的一个attribute,如一个函数或变量

这种情况下,执行该package时会抛出circular import error错误,即循环引用,因为module_a试图去引入module_b时,而module_b首先要引入module_a,这会导致Python解释器无法执行下去。

然而,我们可以通过一些巧妙的方法,让上面的逻辑正常工作,同时避免循环引入的错误。

那么,什么时候它能正常工作,什么时候不能正常工作,而那些能够正常工作的情况又是什么原因呢?

何时它能正常工作?

 1. 在module顶部引入,不要用from,相对引入,只在Python 2中有效

在module的顶部import,如import another_module,module 中的函数以another_module.attribute的方式引用another_module中的函数或变量等。这种方式之所以有效,是由于import another_module是基于当前目录的相对引用,而且是一种隐式引用,如果从另一个package中引入module时,就可以失效了。另外,import another_module这种语法在Python3 中已经不支持了,所以不要在代码中用这种方法来避免循环引入。

如:

# pkg/module_a.py 
from __future__ import print_function
import module_b
 
def action_a():
 print(module_b.action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
import module_a
 
def action_b():
 print(module_a.action_a.__name__)

2. 在module的顶部引入,不要用from,绝对引入

在module的顶部import,使用从package开始的绝对路径,如import package.another_module,module 中的函数以package.another_module.attribute的方式引用another_module中的函数或变量等。之所以要挂上package name来引入,是由于import .another_module这种形式的“相对引入”会报语法错误,而挂上package的绝对引入,Python 2和3都支持

案例:

# pkg/module_a.py
from __future__ import print_function
import pkg2.module_b
 
def action_a():
 print(pkg2.module_b.action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
import pkg2.module_a
 
def action_b():
 print(pkg2.module_a.action_a.__name__)

3. 在module底部引入another module的attribute,而非another module,用from

在module的底部import(至少要在被引用的attribute之后import),直接引入another module的attribute,如from package.another_module import attribute,相对引入也支持,如from .another_module import attribute,module中的函数直接使用被引用的attribute即可。

如:

# pkg/module_a.py
from __future__ import print_function
 
def action_a():
 print(action_b.__name__)
 
from .module_b import action_b
 
 
# pkg/module_b.py
from __future__ import print_function
 
def action_b():
 print(action_a.__name__)
 
from .module_a import action_a

4. 函数顶部引入,可以用from

在module的function顶部import,如from package import another_module,也支持相对引入,引入module或attribute均可。

如:

# pkg/module_a.py
from __future__ import print_function
 
def action_a():
 from . import module_b
 print(module_b.action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
 
def action_b():
 from . import module_a
 print(module_a.action_a.__name__)

# pkg/module_a.py
from __future__ import print_function
 
def action_a():
 from .module_b import action_b
 print(action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
def action_b():
 from .module_a import action_a
 print(action_a.__name__)

这种方式虽然Python 2和3都支持,但编码不够优雅,影响代码可读性,不建议使用


本文讨论的问题,是Python中调用package时,应如何避免循环引入

当直接在命令行执行一个Python module时,适用情况不完全相同

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python实现自动登录人人网并访问最近来访者实例
Sep 26 Python
Python黑魔法Descriptor描述符的实例解析
Jun 02 Python
python验证码识别的实例详解
Sep 09 Python
python字符串中的单双引
Feb 16 Python
python+selenium实现京东自动登录及秒杀功能
Nov 18 Python
Python格式化输出字符串方法小结【%与format】
Oct 29 Python
对numpy中二进制格式的数据存储与读取方法详解
Nov 01 Python
Python+OpenCV图片局部区域像素值处理详解
Jan 23 Python
用Python实现校园通知更新提醒功能
Nov 23 Python
python shapely.geometry.polygon任意两个四边形的IOU计算实例
Apr 12 Python
使用keras根据层名称来初始化网络
May 21 Python
PIP和conda 更换国内安装源的方法步骤
Sep 21 Python
Python实现随机选择元素功能
Sep 14 #Python
python自动化脚本安装指定版本python环境详解
Sep 14 #Python
python实现八大排序算法(2)
Sep 14 #Python
Python3.4编程实现简单抓取爬虫功能示例
Sep 14 #Python
python实现八大排序算法(1)
Sep 14 #Python
python实现简单聊天应用 python群聊和点对点均实现
Sep 14 #Python
Python实现购物系统(示例讲解)
Sep 13 #Python
You might like
分享最受欢迎的5款PHP框架
2014/11/27 PHP
Apache连接PHP后无法启动问题解决思路
2015/06/18 PHP
详解php的socket通信
2015/08/11 PHP
php函数传值的引用传递注意事项分析
2016/06/25 PHP
浅谈php的TS和NTS的区别
2019/03/13 PHP
JavaScript操作XML实例代码(获取新闻标题并分页,并分页)
2010/05/25 Javascript
ASP.NET jQuery 实例1(在TextBox里面创建一个默认提示)
2012/01/13 Javascript
js中判断Object、Array、Function等引用类型对象是否相等
2012/08/29 Javascript
让AJAX不依赖后端接口实现方案
2012/12/03 Javascript
jquery 面包屑导航 具体实现
2013/06/05 Javascript
jQuery客户端分页实例代码
2013/11/18 Javascript
jquery实现动画菜单的左右滚动、渐变及图形背景滚动等效果
2015/08/25 Javascript
jQuery实现自定义右键菜单的树状菜单效果
2015/09/02 Javascript
浅谈js中的in-for循环
2016/06/28 Javascript
node.js学习之base64编码解码
2016/10/21 Javascript
Javascript 跨域知识详细介绍
2016/10/30 Javascript
微信JS-SDK自定义分享功能实例详解【分享给朋友/分享到朋友圈】
2016/11/25 Javascript
vue项目中做编辑功能传递数据时遇到问题的解决方法
2016/12/19 Javascript
原生js实现秒表计时器功能
2017/02/16 Javascript
JS原型继承四步曲及原型继承图一览
2017/11/28 Javascript
微信小程序实现富文本图片宽度自适应的方法
2019/01/20 Javascript
python解析模块(ConfigParser)使用方法
2013/12/10 Python
简单解析Django框架中的表单验证
2015/07/17 Python
Python 16进制与中文相互转换的实现方法
2018/07/09 Python
Flask-Mail用法实例分析
2018/07/21 Python
python 统计文件中的字符串数目示例
2019/12/24 Python
关于Keras模型可视化教程及关键问题的解决
2020/01/24 Python
python文件和文件夹复制函数
2020/02/07 Python
我的applet原先好好的, 一放到web server就会有问题,为什么?
2016/05/10 面试题
请用Python写一个获取用户输入数字,并根据数字大小输出不同信息的脚本
2014/05/20 面试题
岗位职责的定义
2013/11/10 职场文书
大二法学专业职业生涯规划范文
2014/02/12 职场文书
公司领导班子对照材料
2014/08/18 职场文书
出售房屋委托书范本
2014/09/24 职场文书
2015年度校学生会工作总结报告
2015/05/23 职场文书
Python集合set()使用的方法详解
2022/03/18 Python