关于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局部赋值的规则
Mar 07 Python
Python脚本实现DNSPod DNS动态解析域名
Feb 14 Python
Python将阿拉伯数字转换为罗马数字的方法
Jul 10 Python
对pycharm代码整体左移和右移缩进快捷键的介绍
Jul 16 Python
python opencv人脸检测提取及保存方法
Aug 03 Python
Python实现监控键盘鼠标操作示例【基于pyHook与pythoncom模块】
Sep 04 Python
对Pandas MultiIndex(多重索引)详解
Nov 16 Python
使用Python快乐学数学Github万星神器Manim简介
Aug 07 Python
python 3.74 运行import numpy as np 报错lib\site-packages\numpy\__init__.py
Oct 06 Python
pytorch实现线性拟合方式
Jan 15 Python
Pycharm制作搞怪弹窗的实现代码
Feb 19 Python
python开发的自动化运维工具ansible详解
Aug 07 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正确配置mysql(apache环境)
2011/08/28 PHP
destoon文章模块调用企业会员资料的方法
2014/08/22 PHP
php批量添加数据与批量更新数据的实现方法
2014/12/16 PHP
php简单随机字符串生成方法示例
2017/04/19 PHP
Laravel给生产环境添加监听事件(SQL日志监听)
2017/06/19 PHP
PHP大文件分割上传 PHP分片上传
2017/08/28 PHP
php生成二维码不保存服务器还有下载功能的实现代码
2018/08/09 PHP
javascript add event remove event
2008/04/07 Javascript
JavaScript中null与undefined分析
2009/07/25 Javascript
Javascript中的变量使用说明
2010/05/18 Javascript
JQuery AJAX 中文乱码问题解决
2013/06/05 Javascript
JavaScript数据类型学习笔记分享
2016/09/01 Javascript
基于JavaScript实现跳转提示页面
2016/09/24 Javascript
深入理解JavaScript定时机制
2016/10/27 Javascript
Vue.js第二天学习笔记(vue-router)
2016/12/01 Javascript
利用js编写网页进度条效果
2017/10/08 Javascript
深入理解node.js http模块
2018/01/24 Javascript
Vue 指令实现按钮级别权限管理功能
2019/04/23 Javascript
JavaScript命名空间模式实例详解
2019/06/20 Javascript
vue router动态路由设置参数可选问题
2019/08/21 Javascript
Javascript前端下载后台传来的文件流代码实例
2020/08/18 Javascript
在Python的web框架中中编写日志列表的教程
2015/04/30 Python
Python基于whois模块简单识别网站域名及所有者的方法
2018/04/23 Python
详解python Todo清单实战
2018/11/01 Python
Python 利用Entrez库筛选下载PubMed文献摘要的示例
2020/11/24 Python
美国保健品专家:Life Extension
2018/05/04 全球购物
西班牙最大的婴儿用品网上商店:Bebitus
2019/05/30 全球购物
家长给幼儿园的表扬信
2014/01/09 职场文书
抗洪抢险事迹材料
2014/05/06 职场文书
白血病捐款倡议书
2014/05/14 职场文书
儿童生日会策划方案
2014/05/15 职场文书
纪检干部现实表现材料
2014/08/21 职场文书
远程培训的心得体会
2014/09/01 职场文书
乡镇党的群众路线教育实践活动个人整改方案
2014/10/31 职场文书
尊师重教主题班会
2015/08/14 职场文书
2016年寒假学习心得体会
2015/10/09 职场文书