关于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编程过程中用单元测试法调试代码的介绍
Apr 02 Python
python登录pop3邮件服务器接收邮件的方法
Apr 30 Python
Win7下搭建python开发环境图文教程(安装Python、pip、解释器)
May 17 Python
Python pass详细介绍及实例代码
Nov 24 Python
python opencv旋转图像(保持图像不被裁减)
Jul 26 Python
python调用摄像头显示图像的实例
Aug 03 Python
在python中pandas读文件,有中文字符的方法
Dec 12 Python
Python Web框架之Django框架Form组件用法详解
Aug 16 Python
django-csrf使用和禁用方式
Mar 13 Python
Python3爬虫中Selenium的用法详解
Jul 10 Python
python调用百度AI接口实现人流量统计
Feb 03 Python
python 对xml解析的示例
Feb 27 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 和 COM
2006/10/09 PHP
php生成SessionID和图片校验码的思路和实现代码
2009/03/10 PHP
如何突破PHP程序员的技术瓶颈分析
2011/07/17 PHP
php实现发送微信模板消息的方法
2015/03/07 PHP
PHP使用Redis长连接的方法详解
2018/02/12 PHP
PHP的微信支付接口使用方法讲解
2019/03/08 PHP
如何利用PHP实现上传图片功能详解
2020/09/24 PHP
js限制文本框只能输入数字(正则表达式)
2012/07/15 Javascript
得到form下的所有的input的js代码
2013/11/07 Javascript
firefox浏览器用jquery.uploadify插件上传时报HTTP 302错误
2015/03/01 Javascript
详解AngularJS中的依赖注入机制
2015/06/17 Javascript
JavaScript实现点击自动选择TextArea文本的方法
2015/07/02 Javascript
JavaScript使用RegExp进行正则匹配的方法
2015/07/11 Javascript
简介EasyUI datagrid editor combogrid搜索框的实现
2016/04/01 Javascript
AngularJS基础 ng-focus 指令简单示例
2016/08/01 Javascript
很棒的js Tab选项卡切换效果
2016/08/30 Javascript
jQuery基于随机数解决中午吃什么去哪吃问题示例
2018/12/29 jQuery
vue车牌号校验和银行校验实战
2019/01/23 Javascript
jQuery实现的网站banner图片无缝轮播效果完整实例
2019/01/28 jQuery
vue中jsonp插件的使用方法示例
2020/09/10 Javascript
[59:26]DOTA2上海特级锦标赛D组资格赛#1 EG VS VP第二局
2016/02/28 DOTA
[47:31]完美世界DOTA2联赛PWL S3 INK ICE vs DLG 第一场 12.12
2020/12/16 DOTA
python的urllib模块显示下载进度示例
2014/01/17 Python
vc6编写python扩展的方法分享
2014/01/17 Python
Python通过解析网页实现看报程序的方法
2014/08/04 Python
Python读取环境变量的方法和自定义类分享
2014/11/22 Python
举例详解Python中的split()函数的使用方法
2015/04/07 Python
pandas DataFrame实现几列数据合并成为新的一列方法
2018/06/08 Python
python fuzzywuzzy模块模糊字符串匹配详细用法
2019/08/29 Python
Python实现图像的垂直投影示例
2020/01/17 Python
奇怪的鱼:Weird Fish
2018/03/18 全球购物
毕业生求职简历中的自我评价
2013/10/18 职场文书
井冈山红色之旅感想
2014/10/07 职场文书
HR必备:超全面的薪酬待遇管理方案!
2019/07/12 职场文书
交互式可视化js库gojs使用介绍及技巧
2022/02/18 Javascript
Python OpenCV超详细讲解基本功能
2022/04/02 Python