(2022.11.06 Sun)
在Python执行import xxx
操作有两种方式,absolute import和relative import。在介绍这两种导入方式前,先看看Python在执行import xxx
命令时发生了什么。
导入路径和环境变量
执行命令
>> import xyz
执行过程中,Python所做的第一件事是检索缓存(cache)sys.modules
,该缓存中保存了所有之前已经导入的模块(modules)。
>> sys.modules
{'sys': , 'builtins': , '_frozen_importlib': , '_imp': , '_thread': , '_warnings': , '_weakref': , '_io': , ...}
如果导入的module/package名xyz
不在模块缓存sys.modules
中,则Python继续检测内建modules列表。这些模块在使用前已经安装过保存在Python标准库中(Python Standard Library)。如果xyz
仍然不在该内建modules列表中,Python会在类似于环境变量的路径中sys.path
寻找该module。在sys.path
中,当前路径处在列表的index=0的位置。
总结Python在执行import xyz
时执行查找的顺序依次是
已经导入的模块缓存
sys.modules
Python标准库/built-in module list
(类环境变量的)路径列表
sys.path
当Python找到该模块,会将该模块与本地范围(local scope)绑定,也就是xyz
被定义并可在当前文件中使用而不必抛出NameError
异常。
如果没找到该名字对应的模块,则抛出ModuleNotFoundError
异常。
导入的对象包括packages和modules,或者其中的特定对象比如方法或属性或类。在导入package时,导入的实则是该package中的__init__.py
文件,并将其作为module导入。
导入的顺序
导入的package/module分为三种
Python系统内建的module
第三方modules
使用者指定的文件
在导入时,习惯上按上面顺序导入各自部分,每种module内部按字母顺序/字典顺序依次导入。比如
import functools
import os
import Flask
import pandas as pd
import user_defined_modules
Absolute import Vs. Relative import
简而言之,absolute import和relative import的区别在于执行import
命令时是否给定导入对象的(基于项目跟目录的)完整路径名称。以项目import_test_case
为例,用tree
找到该项目内的文件结构如下
$ tree
...
├── import_test_case
│ ├── module1.py
│ ├── package1
│ │ ├── __init__.py
│ │ └── module11.py
│ └── package2
│ └── package3
│ └── module31.py
...
假设项目根目录下的package1
中的module11.py
中有一个函数需要引用项目根目录下module1.py
文件中的函数function1
,则module11.py
文件中的绝对导入方法为
import module1.function1
即在导入时给出基于项目根目录的绝对路径。
该表达的优势在于
路径指明清晰、直接,可以直接看到导入的源在哪里
即便导入指令所在文件的当前路径发生变化,导入指令也无需修改,PEP 8推荐绝对导入方式
劣势
- 在特定情况下导入命令冗长(verbose),比如项目文件的结构复杂和深,如下面这个导入
from package1.package11.package111.package1111 import module1111
而relative import则使用了Unix的惯用表达,即用一个表示当前文件夹,两个点表示parent directory,三个点表示grandparent directory。
from ..package2 import module2
relative import的优势
- 简洁(succinct),由当前执行导入命令的位置决定导入命令,比如上面absolute import方法中的复杂文件夹
from package1.package11.package111.package1111 import module1111
导入命令发生在package1112
文件夹下,则该指令表示为
from ..package1111 import module1111
劣势
- 在共享/协作开发饿项目中,项目结构会发生变化,文件位置也可能发生变化,则这种情况下相对导入变得不可读且可能无效。
Reference
1 realpython, absolute vs relative python imports