关于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内置函数Type()函数一个有趣的用法
Feb 18 Python
Python中一些自然语言工具的使用的入门教程
Apr 13 Python
python 写的一个爬虫程序源码
Feb 28 Python
python中set()函数简介及实例解析
Jan 09 Python
Python实现类似比特币的加密货币区块链的创建与交易实例
Mar 20 Python
python搭建服务器实现两个Android客户端间收发消息
Apr 12 Python
对python 匹配字符串开头和结尾的方法详解
Oct 27 Python
Opencv实现抠图背景图替换功能
May 21 Python
Python 创建守护进程的示例
Sep 29 Python
python实现在列表中查找某个元素的下标示例
Nov 16 Python
教你怎么用python selenium实现自动化测试
May 27 Python
python人工智能human learn绘图可创建机器学习模型
Nov 23 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连接sftp并下载文件的方法教程
2018/08/26 PHP
tp5框架使用composer实现日志记录功能示例
2019/01/10 PHP
基于jquery实现的类似百度搜索的输入框自动完成功能
2011/08/23 Javascript
javascript小组件 原生table排序表格脚本(兼容ie firefox opera chrome)
2012/07/25 Javascript
Jquery判断$("#id")获取的对象是否存在的方法
2013/09/25 Javascript
js history对象简单实现返回和前进
2013/10/30 Javascript
JQuery Highcharts 动态生成图表的方法
2013/11/15 Javascript
最丑的时钟效果!js canvas时钟制作方法
2016/08/15 Javascript
微信小程序 时间格式化(util.formatTime(new Date))详解
2016/11/16 Javascript
JS实现基于Sketch.js模拟成群游动的蝌蚪运动动画效果【附demo源码下载】
2017/08/18 Javascript
如何在 JavaScript 中更好地利用数组
2018/09/27 Javascript
基于vue和react的spa进行按需加载的实现方法
2018/09/29 Javascript
js中怎么判断两个字符串相等的实例
2019/01/17 Javascript
JavaScript数据结构与算法之基本排序算法定义与效率比较【冒泡、选择、插入排序】
2019/02/21 Javascript
JavaScript+HTML5 canvas实现放大镜效果完整示例
2019/05/15 Javascript
Vue.js中该如何自己维护路由跳转记录
2019/05/19 Javascript
js类的继承定义与用法分析
2019/06/21 Javascript
微信小程序 可搜索的地址选择实现详解
2019/08/28 Javascript
js脚本中执行java后台代码方法解析
2019/10/11 Javascript
[00:35]2016完美“圣”典风云人物:冷冷宣传片
2016/12/08 DOTA
跟老齐学Python之使用Python操作数据库(1)
2014/11/25 Python
详解Python操作RabbitMQ服务器消息队列的远程结果返回
2016/06/30 Python
浅析Python与Mongodb数据库之间的操作方法
2019/07/01 Python
基于Python2、Python3中reload()的不同用法介绍
2019/08/12 Python
详解Python并发编程之创建多线程的几种方法
2019/08/23 Python
使用 tf.nn.dynamic_rnn 展开时间维度方式
2020/01/21 Python
python爬取音频下载的示例代码
2020/10/19 Python
Nike比利时官网:Nike.com (BE)
2019/02/07 全球购物
什么是.net的Remoting技术
2016/07/08 面试题
为什么需要版本控制
2016/10/28 面试题
长辈证婚人证婚词
2014/01/09 职场文书
时尚休闲吧创业计划书
2014/01/25 职场文书
祖国在我心中演讲稿400字
2014/05/04 职场文书
医德医风演讲稿
2014/05/20 职场文书
2014个人四风对照检查材料思想汇报
2014/09/18 职场文书
MySQL数据库索引的最左匹配原则
2021/11/20 MySQL