详解Python中的相对导入和绝对导入


Posted in Python onJanuary 06, 2017

前言

Python 相对导入与绝对导入,这两个概念是相对于包内导入而言的。包内导入即是包内的模块导入包内部的模块。

Python import 的搜索路径

  1. 在当前目录下搜索该模块
  2. 在环境变量 PYTHONPATH 中指定的路径列表中依次搜索
  3. 在 Python 安装路径的 lib 库中搜索

Python import 的步骤

python 所有加载的模块信息都存放在 sys.modules 结构中,当 import 一个模块时,会按如下步骤来进行

  1. 如果是 import A,检查 sys.modules 中是否已经有 A,如果有则不加载,如果没有则为 A 创建 module 对象,并加载 A
  2. 如果是 from A import B,先为 A 创建 module 对象,再解析A,从中寻找B并填充到 A 的 __dict__

相对导入与绝对导入

绝对导入的格式为 import A.Bfrom A import B,相对导入格式为 from . import Bfrom ..A import B,.代表当前模块,..代表上层模块,...代表上上层模块,依次类推。

相对导入可以避免硬编码带来的维护问题,例如我们改了某一顶层包的名,那么其子包所有的导入就都不能用了。但是 存在相对导入语句的模块,不能直接运行,否则会有异常:

ValueError: Attempted relative import in non-package

这是什么原因呢?我们需要先来了解下导入模块时的一些规则:

在没有明确指定包结构的情况下,Python 是根据 __name__ 来决定一个模块在包中的结构的,如果是 __main__ 则它本身是顶层模块,没有包结构,如果是A.B.C 结构,那么顶层模块是 A。基本上遵循这样的原则:

  1. 如果是绝对导入,一个模块只能导入自身的子模块或和它的顶层模块同级别的模块及其子模块
  2. 如果是相对导入,一个模块必须有包结构且只能导入它的顶层模块内部的模块

如果一个模块被直接运行,则它自己为顶层模块,不存在层次结构,所以找不到其他的相对路径。

Python2.x 缺省为相对路径导入,Python3.x 缺省为绝对路径导入。绝对导入可以避免导入子包覆盖掉标准库模块(由于名字相同,发生冲突)。如果在 Python2.x 中要默认使用绝对导入,可以在文件开头加入如下语句:

from __future__ import absolute_import

from __future__ import absolute_import

这句 import 并不是指将所有的导入视为绝对导入,而是指禁用 implicit relative import(隐式相对导入), 但并不会禁掉 explicit relative import(显示相对导入)。

那么到底什么是隐式相对导入,什么又是显示的相对导入呢?我们来看一个例子,假设有如下包结构:

thing
├── books
│ ├── adventure.py
│ ├── history.py
│ ├── horror.py
│ ├── __init__.py
│ └── lovestory.py
├── furniture
│ ├── armchair.py
│ ├── bench.py
│ ├── __init__.py
│ ├── screen.py
│ └── stool.py
└── __init__.py

那么如果在 stool 中引用 bench,则有如下几种方式:

import bench     # 此为 implicit relative import
from . import bench   # 此为 explicit relative import
from furniture import bench # 此为 absolute import

隐式相对就是没有告诉解释器相对于谁,但默认相对与当前模块;而显示相对则明确告诉解释器相对于谁来导入。以上导入方式的第三种,才是官方推荐的,第一种是官方强烈不推荐的,Python3 中已经被废弃,这种方式只能用于导入 path 中的模块。

相对与绝对仅针对包内导入而言

最后再次强调,相对导入与绝对导入仅针对于包内导入而言,要不然本文所讨论的内容就没有意义。所谓的包,就是包含 __init__.py 文件的目录,该文件在包导入时会被首先执行,该文件可以为空,也可以在其中加入任意合法的 Python 代码。

相对导入可以避免硬编码,对于包的维护是友好的。绝对导入可以避免与标准库命名的冲突,实际上也不推荐自定义模块与标准库命令相同。

前面提到含有相对导入的模块不能被直接运行,实际上含有绝对导入的模块也不能被直接运行,会出现 ImportError:

ImportError: No module named XXX

这与绝对导入时是一样的原因。要运行包中包含绝对导入和相对导入的模块,可以用 python -m A.B.C 告诉解释器模块的层次结构。

有人可能会问:假如有两个模块 a.py 和 b.py 放在同一个目录下,为什么能在 b.py 中 import a 呢?

这是因为这两个文件所在的目录不是一个包,那么每一个 python 文件都是一个独立的、可以直接被其他模块导入的模块,就像你导入标准库一样,它们不存在相对导入和绝对导入的问题。相对导入与绝对导入仅用于包内部。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用python能有一定的帮助,如果有疑问大家可以留言交流。

Python 相关文章推荐
python批量替换页眉页脚实例代码
Jan 22 Python
Linux系统(CentOS)下python2.7.10安装
Sep 26 Python
Python3实现对列表按元组指定列进行排序的方法分析
Dec 22 Python
Python设计模式之享元模式原理与用法实例分析
Jan 11 Python
python 利用pandas将arff文件转csv文件的方法
Feb 12 Python
pandas dataframe的合并实现(append, merge, concat)
Jun 24 Python
python挖矿算力测试程序详解
Jul 03 Python
Kears+Opencv实现简单人脸识别
Aug 28 Python
pycharm显示远程图片的实现
Nov 04 Python
在python中创建指定大小的多维数组方式
Nov 28 Python
用Python绘制漫步图实例讲解
Feb 26 Python
15个Pythonic的代码示例(值得收藏)
Oct 29 Python
Python中取整的几种方法小结
Jan 06 #Python
Python正则表达式实现截取成对括号的方法
Jan 06 #Python
关于Python元祖,列表,字典,集合的比较
Jan 06 #Python
Python线程指南详细介绍
Jan 05 #Python
Python爬虫代理IP池实现方法
Jan 05 #Python
在 Python 应用中使用 MongoDB的方法
Jan 05 #Python
深入理解python对json的操作总结
Jan 05 #Python
You might like
编写Smarty插件在模板中直接加载数据的详细介绍
2013/06/26 PHP
PHP遍历并打印指定目录下所有文件实例
2014/02/10 PHP
php提取字符串中网站url地址的方法
2014/12/03 PHP
php将一维数组转换为每3个连续值组成的二维数组
2016/05/06 PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
2016/12/12 PHP
php写一个函数,实现扫描并打印出自定目录下(含子目录)所有jpg文件名
2017/05/26 PHP
JS 如果改变span标签的是否隐藏属性
2011/10/06 Javascript
jquery实现excel导出的方法
2013/04/04 Javascript
2014 年最热门的21款JavaScript框架推荐
2014/12/25 Javascript
JavaScript实现文字与图片拖拽效果的方法
2015/02/16 Javascript
jQuery+slidereveal实现的面板滑动侧边展出效果
2015/03/14 Javascript
jQuery遮罩层实现方法实例详解(附遮罩层插件)
2015/12/08 Javascript
JS实现中文汉字按拼音排序的方法
2017/10/09 Javascript
vue中子组件向父组件传递数据的实例代码(实现加减功能)
2018/04/20 Javascript
详解多页应用 Webpack4 配置优化与踩坑记录
2018/10/16 Javascript
JS/jQuery实现简单的开关灯效果【案例】
2019/02/19 jQuery
解决 viewer.js 动态更新图片导致无法预览的问题
2019/05/14 Javascript
bootstrap 日期控件 datepicker被弹出框dialog覆盖的解决办法
2019/07/09 Javascript
layui 中select下拉change事件失效的解决方法
2019/09/20 Javascript
使用Python的Tornado框架实现一个一对一聊天的程序
2015/04/25 Python
ubuntu系统下 python链接mysql数据库的方法
2017/01/09 Python
python数据预处理之将类别数据转换为数值的方法
2017/07/05 Python
python中文件变化监控示例(watchdog)
2017/10/16 Python
python编程羊车门问题代码示例
2017/10/25 Python
python中 * 的用法详解
2019/07/10 Python
Python图像处理PIL各模块详细介绍(推荐)
2019/07/17 Python
如何基于Python获取图片的物理尺寸
2019/11/25 Python
python三引号如何输入
2020/07/06 Python
python 邮件检测工具mmpi的使用
2021/01/04 Python
俄罗斯一家时尚女装商店:Charuel
2019/12/04 全球购物
大学生毕业求职信
2014/06/12 职场文书
2015年公司工作总结
2015/04/25 职场文书
研究生学习计划书应该怎么写?
2019/09/10 职场文书
JS代码编译器Monaco使用方法
2021/06/11 Javascript
mysql创建存储过程及函数详解
2021/12/04 MySQL
nginx搭建NFS网络文件系统
2022/04/14 Servers