关于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中字符串的格式化方法小结
May 03 Python
Python3实现并发检验代理池地址的方法
Sep 18 Python
python实现发送邮件及附件功能
Mar 02 Python
快速了解python leveldb
Jan 18 Python
Python爬虫小技巧之伪造随机的User-Agent
Sep 13 Python
python opencv 二值化 计算白色像素点的实例
Jul 03 Python
Python解析json时提示“string indices must be integers”问题解决方法
Jul 31 Python
Django重设Admin密码过程解析
Feb 10 Python
如何使用Python进行PDF图片识别OCR
Jan 22 Python
Python爬取梨视频的示例
Jan 29 Python
Python基础之pandas数据合并
Apr 27 Python
详解MindSpore自定义模型损失函数
Jun 30 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
全国FM电台频率大全 - 14 江西省
2020/03/11 无线电
PHP在线生成二维码代码(google api)
2013/06/03 PHP
PHP批量采集下载美女图片的实现代码
2013/06/03 PHP
PHP函数func_num_args用法实例分析
2015/12/07 PHP
文字幻灯片
2006/06/26 Javascript
仅Firefox中链接A无法实现模拟点击以触发其默认行为
2011/07/31 Javascript
nodejs微信扫码支付功能实现
2018/02/17 NodeJs
echarts整合多个类似option的方法实例
2018/07/10 Javascript
详解Node.js 中使用 ECDSA 签名遇到的坑
2018/11/26 Javascript
微信小程序基于picker实现级联菜单
2019/02/15 Javascript
微信小程序学习笔记之本地数据缓存功能详解
2019/03/29 Javascript
详解vue-cli+es6引入es5写的js(两种方法)
2019/04/19 Javascript
JS中的继承操作实例总结
2020/06/06 Javascript
vue监听浏览器原生返回按钮,进行路由转跳操作
2020/09/09 Javascript
[50:27]Secret vs VG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
编程语言Python的发展史
2014/09/26 Python
Python的Twisted框架上手前所必须了解的异步编程思想
2016/05/25 Python
详解python使用递归、尾递归、循环三种方式实现斐波那契数列
2018/01/16 Python
对Python中type打开文件的方式介绍
2018/04/28 Python
python实现批量注册网站用户的示例
2019/02/22 Python
python使用mitmproxy抓取浏览器请求的方法
2019/07/02 Python
Python占用的内存优化教程
2019/07/28 Python
python3中rank函数的用法
2019/11/27 Python
安装Anaconda3及使用Jupyter的方法
2020/10/27 Python
python推导式的使用方法实例
2021/02/28 Python
CSS实现限制字数功能当对象内文本溢出时显示省略标记
2014/08/20 HTML / CSS
美国最大的骑马用品零售商:HorseLoverZ
2017/01/12 全球购物
C#里面如何判断一个Object是否是某种类型(如Boolean)?
2016/02/10 面试题
领班岗位职责范文
2014/02/06 职场文书
2014财务人员自我评价范文
2014/09/21 职场文书
党支部半年考察意见
2015/06/01 职场文书
小学体育队列队形教学反思
2016/02/16 职场文书
Python中的min及返回最小值索引的操作
2021/05/10 Python
SQL IDENTITY_INSERT作用案例详解
2021/08/23 MySQL
python机器学习创建基于规则聊天机器人过程示例详解
2021/11/02 Python
《遗弃》开发商删推文要跑路?官方回应:还在开发
2022/04/03 其他游戏