背景:
在学习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 的默认绝对搜索路径特性
需要注意的是文件夹被python解释器视作package需要满足两个条件:
- 1.文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件。
- 2.不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口)。
所以,当用.. 或 ../..返回上级去导入的时候,如果到了程序的入口就会报错:ValueError: attempted relative import beyond top-level package
这是因为第2条的原因,也就是相对导入的时候不能返回到顶层目录去导入,否则会报错。
所以,用绝对导入的人比较多,相对导入中一个点(同级导入)用的比较多。