关于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代码实例
Feb 04 Python
Python编程中运用闭包时所需要注意的一些地方
May 02 Python
Python下线程之间的共享和释放示例
May 04 Python
理解python正则表达式
Jan 15 Python
2018年Python值得关注的开源库、工具和开发者(总结篇)
Jan 04 Python
教你用Python创建微信聊天机器人
Mar 31 Python
python之Flask实现简单登录功能的示例代码
Dec 24 Python
Python 元组操作总结
Sep 18 Python
pygame实现俄罗斯方块游戏(AI篇1)
Oct 29 Python
python list数据等间隔抽取并新建list存储的例子
Nov 27 Python
python__new__内置静态方法使用解析
Jan 07 Python
安装不同版本的tensorflow与models方法实现
Feb 20 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
PHP中的替代语法简介
2014/08/22 PHP
php常用图片处理类
2016/03/16 PHP
Zend Framework实现多服务器共享SESSION数据的方法
2016/03/22 PHP
javascript CSS画图之基础篇
2009/07/29 Javascript
jQuery 类twitter的文本字数限制带提示效果插件
2010/04/16 Javascript
验证javascript中Object和Function的关系的三段简单代码
2010/06/27 Javascript
解决iframe的frameborder在chrome/ff/ie下的差异
2010/08/12 Javascript
jQuery实现单行文字间歇向上滚动源代码
2013/06/02 Javascript
jQuery 属性选择器element[herf*='value']使用示例
2013/10/20 Javascript
document.compatMode的CSS1compat使用介绍
2014/04/03 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(基于jquery)
2015/11/18 Javascript
JS实现的仿淘宝交易倒计时效果
2015/11/27 Javascript
jQuery动态添加及删除表单上传元素的方法(附demo源码下载)
2016/01/15 Javascript
javascript仿京东导航左侧分类导航下拉菜单效果
2020/11/25 Javascript
JavaScript中的事件委托及好处
2016/07/12 Javascript
AngularJS ng-style中使用filter
2016/09/21 Javascript
vue+elementUI实现图片上传功能
2019/08/20 Javascript
KnockoutJS数组比较算法实例详解
2019/11/25 Javascript
Vue +WebSocket + WaveSurferJS 实现H5聊天对话交互的实例
2020/11/18 Vue.js
[01:08:32]DOTA2-DPC中国联赛 正赛 DLG vs PHOENIX BO3 第二场 1月18日
2021/03/11 DOTA
Python循环语句之break与continue的用法
2015/10/14 Python
Python的Django REST框架中的序列化及请求和返回
2016/04/11 Python
利用numpy+matplotlib绘图的基本操作教程
2017/05/03 Python
python中logging包的使用总结
2018/02/28 Python
python 编写简单网页服务器的实例
2018/06/01 Python
python自动化生成IOS的图标
2018/11/13 Python
python 执行文件时额外参数获取的实例
2018/12/18 Python
通过PYTHON来实现图像分割详解
2019/06/26 Python
MIRTA官网:手工包,100%意大利制造
2020/02/11 全球购物
作为网站管理者应当如何防范XSS
2014/08/16 面试题
开学典礼决心书
2014/03/11 职场文书
2014年卫生院工作总结
2014/12/03 职场文书
2016五一手机促销广告语
2016/01/28 职场文书
2016年社区文体活动总结
2016/04/06 职场文书
浅谈Vue的computed计算属性
2022/03/21 Vue.js
GO语言字符串处理函数之处理Strings包
2022/04/14 Golang