Python imports, 2022.11.06

(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

你可能感兴趣的:(Python imports, 2022.11.06)