关于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 链接和操作 memcache方法
Mar 04 Python
python使用itchat实现手机控制电脑
Feb 22 Python
python如何派生内置不可变类型并修改实例化行为
Mar 21 Python
python用pandas数据加载、存储与文件格式的实例
Dec 07 Python
python中用logging实现日志滚动和过期日志删除功能
Aug 20 Python
Python3 合并二叉树的实现
Sep 30 Python
python 普通克里金(Kriging)法的实现
Dec 19 Python
python数据库编程 ODBC方式实现通讯录
Mar 27 Python
解决Python在导入文件时的FileNotFoundError问题
Apr 10 Python
python 实现任务管理清单案例
Apr 25 Python
使用PyWeChatSpy自动回复微信拍一拍功能的实现代码
Jul 02 Python
python中entry用法讲解
Dec 04 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 购物车实例(申精)
2009/05/11 PHP
解析如何去掉CodeIgniter URL中的index.php
2013/06/25 PHP
ThinkPHP连接数据库及主从数据库的设置教程
2014/08/22 PHP
在php和MySql中计算时间差的方法详解
2015/03/27 PHP
PHP利用超级全局变量$_GET来接收表单数据的实例
2016/11/05 PHP
php 一维数组的循环遍历实现代码
2017/04/10 PHP
JS 动态获取节点代码innerHTML分析 [IE,FF]
2009/11/30 Javascript
JS组件Bootstrap ContextMenu右键菜单使用方法
2016/04/17 Javascript
javascript对象的相关操作小结
2016/05/16 Javascript
easyui-edatagrid.js实现回车键结束编辑功能的实例
2017/04/12 Javascript
jquery tmpl模板(实例讲解)
2017/09/02 jQuery
详解基于vue-router的动态权限控制实现方案
2017/09/28 Javascript
jQuery实现简单复制json对象和json对象集合操作示例
2018/07/09 jQuery
0基础学习前端开发的一些建议
2020/07/14 Javascript
js实现查询商品案例
2020/07/22 Javascript
解决VUE mounted 钩子函数执行时 img 未加载导致页面布局的问题
2020/07/27 Javascript
[01:19]2014DOTA2国际邀请赛 采访TITAN战队ohaiyo 能赢DK很幸运
2014/07/12 DOTA
python解决字典中的值是列表问题的方法
2013/03/04 Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
2019/08/13 Python
Python range、enumerate和zip函数用法详解
2019/09/11 Python
解决pycharm上的jupyter notebook端口被占用问题
2019/12/17 Python
Python如何实现FTP功能
2020/05/28 Python
html5+css3进度条倒计时动画特效代码【推荐】
2016/03/08 HTML / CSS
西班牙在线宠物商店:zooplus.es
2017/02/24 全球购物
ASOS亚洲:ASOS Asia
2018/03/04 全球购物
美国现代家具网站:Design Within Reach
2018/07/19 全球购物
XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式?
2016/01/12 面试题
自荐信结尾
2013/10/27 职场文书
区域总监的岗位职责
2013/11/21 职场文书
九年级家长会邀请函
2014/01/15 职场文书
司马光教学反思
2014/02/01 职场文书
社区春季防火方案
2014/06/02 职场文书
出售房屋委托书范本
2014/09/24 职场文书
2015年推广普通话演讲稿
2015/03/20 职场文书
2015年防汛工作总结
2015/05/15 职场文书
Python OpenCV 图像平移的实现示例
2021/06/04 Python