Python3 中 的 绝对导入 与 相对导入

oXiaoChong 2020-01-04

背景:

在学习tf的时候,看到了from __future__ import absolute_import,所以登记学习一下。

概览:

一般模块导入规则:
import xxx时搜索文件的优先级如下

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


在 Python 程序启动时进行配置,自动将 top-level file 的 home 目录(或用一个''表示当前工作目录)、PYTHONPATH 设置的目录、.pth 文件里的目录、标准库目录合并成一个 list ,组成每次 import 时 Python 搜索的目录列表,放到sys.path 中

关于sys.path的有关调试

  • python2 版本
~ # python
$ python
Python 2.7.12 (default, Oct  8 2019, 14:14:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
  • python3 版本
$ python3
Python 3.5.2 (default, Oct  8 2019, 13:06:37)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']

Python import 的步骤:

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

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

Python中的绝对导入与相对导入:
相对导入与绝对导入,这两个概念是相对于包内导入而言的。包内导入即是包内的模块导入包内部的模块。
所谓的包,就是包含 init.py 文件的目录,该文件在包导入时会被首先执行,该文件可以为空,也可以在其中加入任意合法的 Python 代码。

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

绝对导入:指明顶层 package 名。比如 import a,Python 会在 sys.path里寻找所有名为 a 的顶层模块。

import A.B 

或

from A import B

相对导入:在不指明 package 名的情况下导入自己这个 package 的模块,表示只在 package 的内部目录中搜索,并且不会搜索位于 sys.path 上某处同名的模块,直接效果就是包模块覆盖了外部的模块。

from . import B 

或 

from ..A import B
# .代表当前模块,..代表上层模块,...代表上上层模块,依次类推。

比如一个 package 下有 a.py 和 b.py 两个文件,在 a.py 里 from . import b 即是相对导入 b.py。

# a.py
from . import b

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

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

from __future__ import absolute_import 
# 在 3.0 以前的旧版本中启用相对导入等特性所必须的 future 语句,表示打开了 Python 3.0 的默认绝对搜索路径特性

相关推荐