Python 导入机制

模块(module) 与 包(package)

包和模块有何区别?

  • 每一个*.py文件都是一个模块
  • 是一个带有__init__.py文件的文件夹

相对导入绝对导入

相对导入与绝对导入有何区别?

  • 相对导入格式类似于from . import a, from ..a import b, from ...a import b, 绝对导入类似于from a import b, import a

  • Python2 默认导入方式是相对导入, Python3默认导入方式是绝对导入

    需要注意的是, 相对导入又分为隐式相对导入(implicit relative )显示相对导入(explicit relative import),

1
2
3
4
5
6
7
8
""" color 目录结构 """
color
├── __init__.py
├── blue
│   ├── __init__.py
│   ├── demo.py
│   └── os.py
├── print_color.py

倘若在demo.py中有

1
2
3
""" demo.py """
import os # 隐式相对导入
from . import os # 显示相对导入

在Python2中, 默认的导入方式是相对导入方式, 因此import os 实际上是导入与demo.py同级的os.py文件, 而不是官方os模块, 在Python2 与Python3 中, from . import os行为都是相同的, 都是导入同级os.py文件,

在Python3中, 默认的导入方式是绝对导入方式, 因此, import os实际上是导入官方os模块

在Python2和Python3中, 两者只对隐式相对导入有不同的处理

那对于Python2,如何设置默认的导入方式为绝对导入?

1
from __future__ import absolute_import  # 设置默认的导入方式为绝对导入

Python导入详细过程

Python import 的搜索路径

  • 当前目录下搜索该模块

  • 在环境变量 PYTHONPATH 中指定的路径列表中依次搜索

  • 在 Python 安装路径的 lib 库中搜索

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运行机制

执行python文件有两种方式, 一种是以-m方式, 一种是不加-m方式, 两者有何区别?

1
2
3
4
5
6
7
""" color 目录结构 """
color
├── __init__.py
├── blue
│   ├── __init__.py
│   └── blue_print.py
├── print_color.py

直接运行Python文件

类似于python demo.py方式的,称为直接运行Python文件, 在执行Python文件内容前, Python总共做了以下几个操作

  • 设置该文件的__name____main__

  • 将文件所在的路径, 加入到sys.path搜索路径中

    这里有几个方面需要注意, 也是no module found模块未找到, 导入错误等问题的根源所在

    如果执行python blue_print.py, 而且, 在blue_print.py相对/绝对导入了print_color.py

    文件, 则会出现print_color模块未找到错误, 这是因为对于python而言, 它是从blue_print所在目录开始寻找所要的模块, 因此当然会找不到print_color模块

    1
    2
    3
    4
    5
     ~/project/tmp/color/blue  python blue_print.py 
    Traceback (most recent call last):
    File "blue_print.py", line 4, in <module>
    from print_color import colors
    ImportError: No module named print_color

    那对于这种报错是否有解决方法?

    python 提供-m 方式来运行Python文件, 以该方式可以解决此类问题!!!

-m 以模块方式运行Python文件

类似于python -m demo方式,其含义是, 以模块方式运行文件

对于上方报错代码,可以以以下方式执行

1
2
3
4
5
6
7
8
# ! /usr/bin/env python
# -*- coding: UTF-8 -*-

from print_color import colors


if __name__ == '__main__':
print('{}.{}'.format(__package__, __name__))
1
2
3
"""打开与blue目录同级路径, 执行如下命令"""    
~/project/tmp/color  python -m blue.blue_print
blue.__main__

可以知道, blue_print.py以模块方式执行, 模块名为blue.__main__, 若是直接执行, 模块名为None.__main__

简单来讲, 如果A文件依赖于上级目录中B, 且间接或直接依赖上上级文件C, 则可以在C所在上级目录通过python -m C.B.A`来执行A中的文件

PYTHONPATH与 PYTHONHOME

  • PYTHONHOME: 定制 Python 标准库的路径

    ​prefix 和 exec_prefix 由你的安装环境决定。在 Unix 系统上一般情况下为 /usr/local 。

    ​如果 PYTHONHOME 被设置为单个目录,那么 prefix 和 exec_prefix 都会被设定为该目录。

    ​如果分别设定这两个值,可以使用 prefix:exec_prefix 格式来设定 PYTHONHOME 。

  • PYTHONPATH:默认的 Python 模块搜索路径。

    它的格式和系统的 PATH 是一样,可以指定多个路径,每个路径可以包含纯 Python 实现的 zip 包,但不支持其它语言实现的 zip 包。

    PYTHONHOME 指定的路径总是会自动添加到 PYTHONPATH 中。

[^参考资料]:

  1. Python环境变量
  2. Python 相对导入与绝对导入
  3. Python相对导入机制详解

本文标题:Python 导入机制

文章作者:定。

发布时间:2017年12月22日 - 12时12分

本文字数:2,327字

原始链接:http://cocofe.cn/2017/12/22/Python 导入机制/

许可协议: Attribution-NonCommercial 4.0

转载请保留以上信息。