关于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基于phantomjs实现导入图片
May 13 Python
python正则中最短匹配实现代码
Jan 16 Python
Python实现按当前日期(年、月、日)创建多级目录的方法
Apr 26 Python
实用自动化运维Python脚本分享
Jun 04 Python
使用Python实现一个栈判断括号是否平衡
Aug 23 Python
python3实现斐波那契数列(4种方法)
Jul 15 Python
python3中的eval和exec的区别与联系
Oct 10 Python
Django将默认的SQLite更换为MySQL的实现
Nov 18 Python
python读写Excel表格的实例代码(简单实用)
Dec 19 Python
Tensorflow轻松实现XOR运算的方式
Feb 03 Python
python 使用三引号时容易犯的小错误
Oct 21 Python
python安装sklearn模块的方法详解
Nov 28 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生成静态页面详解
2006/11/19 PHP
php mail to 配置详解
2014/01/16 PHP
教你在header中隐藏php的版本信息
2016/08/10 PHP
ThinkPHP打水印及设置水印位置的方法
2016/10/14 PHP
php与c 实现按行读取文件实例代码
2017/01/03 PHP
PHP单例模式定义与使用实例详解
2017/02/06 PHP
jquery 表格分页等操作实现代码(pagedown,pageup)
2010/04/11 Javascript
JQuery之拖拽插件实现代码
2011/04/14 Javascript
基于jquery实现图片广告轮换效果代码
2011/07/07 Javascript
JQuery调webservice实现邮箱验证(检测是否可用)
2013/05/21 Javascript
JavaScript中最简洁的编码html字符串的方法
2014/10/11 Javascript
Lab.js初次使用笔记
2015/02/28 Javascript
js中判断变量类型函数typeof的用法总结
2016/08/09 Javascript
jQuery实现别踩白块儿网页版小游戏
2017/01/18 Javascript
微信小程序 出现错误:{"baseresponse":{"errcode":-80002,"errmsg":""}}解决办法
2017/02/23 Javascript
JavaScript实现树的遍历算法示例【广度优先与深度优先】
2017/10/26 Javascript
JavaScript多态与封装实例分析
2018/07/27 Javascript
详解Ubuntu安装angular-cli遇到的坑
2018/09/08 Javascript
利用d3.js实现蜂巢图表带动画效果
2019/09/03 Javascript
浅谈vue异步数据影响页面渲染
2019/10/29 Javascript
浅析VUE防抖与节流
2020/11/24 Vue.js
[22:59]VGJ.S vs VG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python(Tornado)模拟登录小米抢手机
2013/11/12 Python
windows下python之mysqldb模块安装方法
2017/09/07 Python
Python使用uuid库生成唯一标识ID
2020/02/12 Python
HTML5拖拉上传文件的简单实例
2017/01/11 HTML / CSS
南威尔士家居商店:Leekes
2016/10/25 全球购物
兰蔻英国官网:Lancome英国
2019/04/30 全球购物
Monki官网:斯堪的纳维亚的独立时尚品牌
2020/11/09 全球购物
linux面试题参考答案(8)
2016/04/19 面试题
中科软笔试题和面试题
2014/10/07 面试题
业务员岗位职责范本
2013/12/15 职场文书
微型企业创业投资计划书
2014/01/10 职场文书
护理学应聘自荐书范文
2014/02/05 职场文书
2015秋季幼儿园开学通知
2015/07/16 职场文书
2019七夕节祝福语36句,快来收藏吧
2019/08/06 职场文书