关于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中的字符串替换操作示例
Jun 27 Python
Mac中升级Python2.7到Python3.5步骤详解
Apr 27 Python
Python复数属性和方法运算操作示例
Jul 21 Python
Python基于lxml模块解析html获取页面内所有叶子节点xpath路径功能示例
May 16 Python
python读取文本绘制动态速度曲线
Jun 21 Python
Python正则表达式和元字符详解
Nov 29 Python
python 获取页面表格数据存放到csv中的方法
Dec 26 Python
python消费kafka数据批量插入到es的方法
Dec 27 Python
Django中提供的6种缓存方式详解
Aug 05 Python
基于python及pytorch中乘法的使用详解
Dec 27 Python
全网最全python库selenium自动化使用详细教程
Jan 12 Python
python 基于DDT实现数据驱动测试
Feb 18 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
一个可查询所有表的“通用”查询分页类
2006/10/09 PHP
PHP 将图片按创建时间进行分类存储的实现代码
2010/01/05 PHP
php explode函数实例代码
2012/02/27 PHP
CURL状态码列表(详细)
2013/06/27 PHP
[原创]php求圆周率的简单实现方法
2016/05/30 PHP
浅谈PHP正则中的捕获组与非捕获组
2016/07/18 PHP
yii框架使用分页的方法分析
2019/07/25 PHP
EXT中xtype的含义分析
2010/01/07 Javascript
判断ie的两种简单方法
2013/08/12 Javascript
Jquery 的outerHeight方法使用介绍
2013/09/11 Javascript
jquery统计输入文字的个数并对其进行判断
2014/01/07 Javascript
JavaScript中自定义事件用法分析
2014/12/23 Javascript
javascript常用的方法分享
2015/07/01 Javascript
JavaScript学习笔记之数组随机排序
2016/03/23 Javascript
BootStrap Validator使用注意事项(必看篇)
2016/09/28 Javascript
jQuery获取单选按钮radio选中值与去除所有radio选中状态的方法
2017/05/20 jQuery
JavaScript使用闭包模仿块级作用域操作示例
2019/01/21 Javascript
小程序使用watch监听数据变化的方法详解
2019/09/20 Javascript
Python入门教程之if语句的用法
2015/05/14 Python
win7上python2.7连接mysql数据库的方法
2017/01/14 Python
Python中struct模块对字节流/二进制流的操作教程
2017/01/21 Python
Python实现的中国剩余定理算法示例
2017/08/05 Python
深入理解Django的自定义过滤器
2017/10/17 Python
详解Anaconda安装tensorflow报错问题解决方法
2020/11/01 Python
详解HTML5中的元素与元素
2015/08/17 HTML / CSS
html5实现九宫格抽奖可固定抽中某项奖品
2020/06/15 HTML / CSS
印尼最大的在线购物网站:MatahariMall.com
2016/08/26 全球购物
美国价格实惠的在线眼镜网站:Zeelool
2020/12/25 全球购物
北京捷通华声语音技术有限公司Java软件工程师笔试题
2012/04/10 面试题
汽车维修专业毕业生的求职信分享
2013/12/04 职场文书
机电工程学生自荐信范文
2013/12/07 职场文书
财务会计专业求职信
2014/06/09 职场文书
2015年六一儿童节演讲稿
2015/03/19 职场文书
Python正则表达式中flags参数的实例详解
2022/04/01 Python
MySQL中LAG()函数和LEAD()函数的使用
2022/08/14 MySQL
Vue3实现简易音乐播放器组件
2022/08/14 Vue.js