关于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 检查数组元素是否存在类似PHP isset()方法
Oct 14 Python
跟老齐学Python之私有函数和专有方法
Oct 24 Python
Django中使用locals()函数的技巧
Jul 16 Python
python编程羊车门问题代码示例
Oct 25 Python
用Python编写一个简单的CS架构后门的方法
Nov 20 Python
python查看文件大小和文件夹内容的方法
Jul 08 Python
python RC4加密操作示例【测试可用】
Sep 26 Python
浅谈Python类中的self到底是干啥的
Nov 11 Python
Python django框架开发发布会签到系统(web开发)
Feb 12 Python
python能开发游戏吗
Jun 11 Python
基于python requests selenium爬取excel vba过程解析
Aug 12 Python
python使用matplotlib:subplot绘制多个子图的示例
Sep 24 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
Session的工作方式
2006/10/09 PHP
PHP随机数生成代码与使用实例分析
2011/04/08 PHP
php数据类型判断函数有哪些
2013/09/23 PHP
php文件扩展名判断及获取文件扩展名的N种方法
2015/09/12 PHP
PHP中strpos、strstr和stripos、stristr函数分析
2016/06/11 PHP
Laravel中encrypt和decrypt的实现方法
2017/09/24 PHP
PHP面向对象多态性实现方法简单示例
2017/09/27 PHP
PHP实现模拟http请求的方法分析
2017/12/20 PHP
Javascript下的keyCode键码值表
2007/04/10 Javascript
Javascript图像处理—虚拟边缘介绍及使用方法
2012/12/27 Javascript
浏览器打开层自动缓慢展开收缩实例代码
2013/07/04 Javascript
JavaScript实现的内存数据库LokiJS介绍和入门实例
2014/11/17 Javascript
nodejs通过phantomjs实现下载网页
2015/05/04 NodeJs
jQuery form插件之ajaxForm()和ajaxSubmit()的可选参数项对象
2016/01/23 Javascript
Javascript 6里的4个新语法
2016/08/25 Javascript
jQuery异步提交表单的两种方式
2016/09/13 Javascript
js常用DOM方法详解
2017/02/04 Javascript
ionic实现底部分享功能
2017/05/11 Javascript
Node.js操作redis实现添加查询功能
2017/05/25 Javascript
微信小程序scroll-view组件实现滚动动画
2018/01/31 Javascript
详解用Node.js写一个简单的命令行工具
2018/03/01 Javascript
Vue插件打包与发布的方法示例
2018/08/20 Javascript
[02:02]特效爆炸!DOTA2珍宝之瓶待你开启
2018/08/21 DOTA
python正则表达式修复网站文章字体不统一的解决方法
2013/02/21 Python
Python使用Numpy模块读取文件并绘制图片
2020/05/13 Python
Sephora丝芙兰马来西亚官方网站:国际化妆品购物
2018/03/15 全球购物
STRATHBERRY苏贝瑞包包官网:西班牙高级工匠手工打造
2020/11/10 全球购物
课改先进个人汇报材料
2014/01/26 职场文书
运动会通讯稿100字
2014/01/31 职场文书
公司门卫管理制度
2014/02/01 职场文书
电气工程及其自动化专业求职信
2014/06/23 职场文书
英语自我介绍演讲稿
2014/09/01 职场文书
党的群众路线教育实践活动心得体会(医院)
2014/11/03 职场文书
人生感悟经典句子
2019/08/20 职场文书
Html分层的box-shadow效果的示例代码
2021/03/30 HTML / CSS
如何打开Win11系统注册表编辑器?Win11注册表编辑器打开修复方法
2022/04/05 数码科技