关于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的类变量和成员变量用法实例教程
Aug 25 Python
Python中下划线的使用方法
Mar 27 Python
python学习数据结构实例代码
May 11 Python
浅谈Python traceback的优雅处理
Aug 31 Python
Python用5行代码写一个自定义简单二维码
Oct 21 Python
python 发送json数据操作实例分析
Oct 15 Python
python3发送request请求及查看返回结果实例
Apr 30 Python
Flask缓存静态文件的具体方法
Aug 02 Python
python实现图书馆抢座(自动预约)功能的示例代码
Sep 29 Python
Python pip 常用命令汇总
Oct 19 Python
PyQt实现计数器的方法示例
Jan 18 Python
Python机器学习工具scikit-learn的使用笔记
Jan 28 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实现密保卡功能实现代码<打包下载直接运行>
2011/10/09 PHP
PHP 在数组中搜索给定的简单实例 array_search 函数
2016/06/13 PHP
PHP生成随机密码4种方法及性能对比
2020/12/11 PHP
JavaScript高级程序设计
2006/12/29 Javascript
javascript之对系统的toFixed()方法的修正
2007/05/08 Javascript
Jquery增加鼠标中间功能mousewheel的实例代码
2013/09/05 Javascript
js转义字符介绍
2013/11/05 Javascript
关于Javascript 对象(object)的prototype
2014/05/09 Javascript
使用jQuery仿苹果官网焦点图特效
2014/12/23 Javascript
JS时间特效最常用的三款
2015/08/19 Javascript
javascript中的正则表达式使用详解
2015/08/30 Javascript
Jquery1.9.1源码分析系列(十五)动画处理之外篇
2015/12/04 Javascript
jQuery获取当前点击的对象元素(实现代码)
2016/05/19 Javascript
jQuery+PHP实现微信转盘抽奖功能的方法
2016/05/25 Javascript
JS简单获取客户端IP地址的方法【调用搜狐接口】
2016/09/05 Javascript
在js中实现邮箱格式的验证方法(推荐)
2016/10/24 Javascript
深入理解javascript函数参数与闭包
2016/12/12 Javascript
Node.js查找当前目录下文件夹实例代码
2017/03/07 Javascript
老生常谈JS中的继承及实现代码
2018/07/06 Javascript
Angular单元测试之事件触发的实现
2020/01/20 Javascript
vue实现tab栏点击高亮效果
2020/08/19 Javascript
vue+iview使用树形控件的具体使用
2020/11/02 Javascript
[01:07]DOTA2次级职业联赛 - Fpb战队宣传片
2014/12/01 DOTA
python微信公众号之关键词自动回复
2018/06/15 Python
CSS3五个技巧给你的网站带来出色的效果
2009/04/02 HTML / CSS
英国天然保健品网站:Simply Supplements
2017/03/22 全球购物
俄罗斯女装店:12storeez
2019/10/25 全球购物
Feelunique澳大利亚:欧洲的化妆品零售电商
2019/12/18 全球购物
婚礼新郎父母答谢词
2014/01/16 职场文书
学校个人对照检查材料
2014/08/26 职场文书
员工激励培训演讲稿
2014/09/16 职场文书
六五普法宣传标语
2014/10/06 职场文书
2015年个人工作总结报告
2015/04/25 职场文书
工作态度恶劣检讨书
2015/05/06 职场文书
费城故事观后感
2015/06/10 职场文书
初中物理教学反思
2016/02/19 职场文书