关于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不规范的日期字符串处理类
Jun 10 Python
Python实现冒泡,插入,选择排序简单实例
Aug 18 Python
python中迭代器(iterator)用法实例分析
Apr 29 Python
Centos Python2 升级到Python3的简单实现
Jun 21 Python
使用python画个小猪佩奇的示例代码
Jun 06 Python
修改python plot折线图的坐标轴刻度方法
Dec 13 Python
Python基于datetime或time模块分别获取当前时间戳的方法实例
Feb 19 Python
python 判断字符串中是否含有汉字或非汉字的实例
Jul 15 Python
Django实现跨域请求过程详解
Jul 25 Python
django写用户登录判定并跳转制定页面的实例
Aug 21 Python
PyCharm+PyQt5+QtDesigner配置详解
Aug 12 Python
python判断字符串以什么结尾的实例方法
Sep 18 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
mysql建立外键
2006/11/25 PHP
PHP通用分页类page.php[仿google分页]
2008/08/31 PHP
php中关于普通表单多文件上传的处理方法
2011/03/25 PHP
zend api扩展的php对象的autoload工具
2011/04/18 PHP
浅析关于PHP位运算的简单权限设计
2013/06/30 PHP
Zend Framework教程之路由功能Zend_Controller_Router详解
2016/03/07 PHP
微信支付开发交易通知实例
2016/07/12 PHP
PHP使用redis消息队列发布微博的方法示例
2017/06/22 PHP
php使用redis的有序集合zset实现延迟队列应用示例
2020/02/20 PHP
jquery 选择器部分整理
2009/10/28 Javascript
JavaScript中将一个值转换为字符串的方法分析[译]
2012/09/21 Javascript
jQuery对象的selector属性用法实例
2014/12/27 Javascript
jQuery实现的纵向下拉菜单实例详解【附demo源码下载】
2016/07/09 Javascript
省市二级联动小案例讲解
2016/07/24 Javascript
微信小程序 MINA文件结构
2016/10/17 Javascript
JS实现页面跳转参数不丢失的方法
2016/11/28 Javascript
用js制作淘宝放大镜效果
2020/10/28 Javascript
基于JavaScript实现的插入排序算法分析
2017/04/14 Javascript
纯JS实现图片验证码功能并兼容IE6-8(推荐)
2017/04/19 Javascript
详解webpack编译多页面vue项目的配置问题
2017/12/11 Javascript
Vue2.0实现组件数据的双向绑定问题
2018/03/06 Javascript
nodejs分离html文件里面的js和css的方法
2019/04/09 NodeJs
webpack-mvc 传统多页面组件化开发详解
2019/05/07 Javascript
js实现窗口全屏示例详解
2019/09/17 Javascript
总结Python编程中函数的使用要点
2016/03/20 Python
python 禁止函数修改列表的实现方法
2017/08/03 Python
Python标准库shutil用法实例详解
2018/08/13 Python
Python设计模式之享元模式原理与用法实例分析
2019/01/11 Python
python数值基础知识浅析
2019/11/19 Python
python调用c++返回带成员指针的类指针实例
2019/12/12 Python
python实现字典嵌套列表取值
2019/12/16 Python
Django视图、传参和forms验证操作
2020/07/15 Python
Debenhams爱尔兰:英国知名的百货公司
2017/01/02 全球购物
轻化专业学生实习自我鉴定
2013/09/20 职场文书
公司领导班子对照材料
2014/08/18 职场文书
幼师自荐信范文(2016推荐篇)
2016/01/28 职场文书