文章插图
作者:pwwang
一、前言本文基于开源项目:
【初窥 Python 的 import 机制】https://github.com/pwwang/Python-import-system补充扩展讲解 , 希望能够让读者一文搞懂 Python 的 import 机制 。
1.1 什么是 import 机制?通常来讲 , 在一段 Python 代码中去执行引用另一个模块中的代码 , 就需要使用 Python 的 import 机制 。import 语句是触发 import 机制最常用的手段 , 但并不是唯一手段 。
importlib.import_module 和 __import__ 函数也可以用来引入其他模块的代码 。
1.2 import 是如何执行的?import 语句会执行两步操作:
- 搜索需要引入的模块
- 将模块的名字作为变量绑定到局部变量中
二、import 机制概览下图是 import 机制的概览图 。不难看出 , 当 import 机制被触发时 , Python 首先会去 sys.modules 中查找该模块是否已经被引入过 , 如果该模块已经被引入了 , 就直接调用它 , 否则再进行下一步 。这里 sys.modules 可以看做是一个缓存容器 。值得注意的是 , 如果 sys.modules 中对应的值是 None 那么就会抛出一个 ModuleNotFoundError 异常 。下面是一个简单的实验:
In [1]: import sysIn [2]: sys.modules['os'] = NoneIn [3]: import os---------------------------------------------------------------------------ModuleNotFoundError Traceback (most recent call last)<ipython-input-3-543d7f3a58ae> in <module>----> 1 import osModuleNotFoundError: import of os halted; None in sys.modules
如果在 sys.modules 找到了对应的 module , 并且这个 import 是由 import 语句触发的 , 那么下一步将对把对应的变量绑定到局部变量中 。如果没有发现任何缓存 , 那么系统将进行一个全新的 import 过程 。在这个过程中 Python 将遍历 sys.meta_path 来寻找是否有符合条件的元路径查找器(meta path finder) 。sys.meta_path 是一个存放元路径查找器的列表 。它有三个默认的查找器:
- 内置模块查找器
- 冻结模块(frozen module)查找器
- 基于路径的模块查找器 。
In [1]: import sysIn [2]: sys.meta_pathOut[2]: [_frozen_importlib.BuiltinImporter, _frozen_importlib.FrozenImporter, _frozen_importlib_external.PathFinder]
查找器的 find_spec 方法决定了该查找器是否能处理要引入的模块并返回一个 ModeuleSpec 对象 , 这个对象包含了用来加载这个模块的相关信息 。如果没有合适的 ModuleSpec 对象返回 , 那么系统将查看 sys.meta_path 的下一个元路径查找器 。如果遍历 sys.meta_path 都没有找到合适的元路径查找器 , 将抛出 ModuleNotFoundError 。引入一个不存在的模块就会发生这种情况 , 因为 sys.meta_path 中所有的查找器都无法处理这种情况:In [1]: import nosuchmodule---------------------------------------------------------------------------ModuleNotFoundError Traceback (most recent call last)<ipython-input-1-40c387f4d718> in <module>----> 1 import nosuchmoduleModuleNotFoundError: No module named 'nosuchmodule'
但是 , 如果这个手动添加一个可以处理这个模块的查找器 , 那么它也是可以被引入的:In [1]: import sys ...: ...: from importlib.abc import MetaPathFinder ...: from importlib.machinery import ModuleSpec ...: ...: class NoSuchModuleFinder(MetaPathFinder): ...: def find_spec(self, fullname, path, target=None): ...: return ModuleSpec('nosuchmodule', None) ...: ...: # don't do this in your script ...: sys.meta_path = [NoSuchModuleFinder()] ...: ...: import nosuchmodule---------------------------------------------------------------------------ImportError Traceback (most recent call last)<ipython-input-6-b7cbf7e60adc> in <module> 11 sys.meta_path = [NoSuchModuleFinder()] 12 ---> 13 import nosuchmoduleImportError: missing loader
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PLC的基本知识?plc的一些基础知识点
- 修复Windows 10更新错误的最佳方法
- 基于SpringBoot的微服务架构与K8S容器部署实践
- 防火墙基础与配置
- 萧何在汉书中属于 成也萧何败也萧何指的是西汉哪位开国功臣
- 朱元璋的郭宁莲是怎么死的 朱元璋老婆郭宁莲
- 哈尔科夫反击战的精妙之处
- 陈平和张良谁更会用计 陈平和张良谁的水平高
- 盗墓笔记里的汪家人是什么来历 盗墓笔记里的汪家人到底是什么人啊
- 这可能是网上最全的 Docker 工具集合