可以看到 , 当我们告诉系统如何去 find_spec 的时候 , 是不会抛出 ModuleNotFound 异常的 。但是要成功加载一个模块 , 还需要加载器 loader 。
加载器是 ModuleSpec 对象的一个属性 , 它决定了如何加载和执行一个模块 。如果说 ModuleSpec 对象是“师父领进门”的话 , 那么加载器就是“修行在个人”了 。在加载器中 , 你完全可以决定如何来加载以及执行一个模块 。这里的决定 , 不仅仅是加载和执行模块本身 , 你甚至可以修改一个模块:
In [1]: import sys ...: from types import ModuleType ...: from importlib.machinery import ModuleSpec ...: from importlib.abc import MetaPathFinder, Loader ...: ...: class Module(ModuleType): ...: def __init__(self, name): ...: self.x = 1 ...: self.name = name ...: ...: class ExampleLoader(Loader): ...: def create_module(self, spec): ...: return Module(spec.name) ...: ...: def exec_module(self, module): ...: module.y = 2 ...: ...: class ExampleFinder(MetaPathFinder): ...: def find_spec(self, fullname, path, target=None): ...: return ModuleSpec('module', ExampleLoader()) ...: ...: sys.meta_path = [ExampleFinder()]In [2]: import moduleIn [3]: moduleOut[3]: <module 'module' (<__main__.ExampleLoader object at 0x7f7f0d07f890>)>In [4]: module.xOut[4]: 1In [5]: module.yOut[5]: 2
从上面的例子可以看到 , 一个加载器通常有两个重要的方法 create_module 和 exec_module 需要实现 。如果实现了 exec_module 方法 , 那么 create_module 则是必须的 。如果这个 import 机制是由 import 语句发起的 , 那么 create_module 方法返回的模块对象对应的变量将会被绑定到当前的局部变量中 。如果一个模块因此成功被加载了 , 那么它将被缓存到 sys.modules 。如果这个模块再次被加载 , 那么 sys.modules 的缓存将会被直接引用 。
文章插图
三、import 勾子(import hooks)为了简化 , 我们在上述的流程图中 , 并没有提到 import 机制的勾子 。实际上你可以添加一个勾子来改变 sys.meta_path 或者 sys.path , 从而来改变 import 机制的行为 。上面的例子中 , 我们直接修改了 sys.meta_path 。实际上 , 你也可以通过勾子来实现:
In [1]: import sys ...: from types import ModuleType ...: from importlib.machinery import ModuleSpec ...: from importlib.abc import MetaPathFinder, Loader ...: ...: class Module(ModuleType): ...: def __init__(self, name): ...: self.x = 1 ...: self.name = name ...: ...: class ExampleLoader(Loader): ...: def create_module(self, spec): ...: return Module(spec.name) ...: ...: def exec_module(self, module): ...: module.y = 2 ...: ...: class ExampleFinder(MetaPathFinder): ...: def find_spec(self, fullname, path, target=None): ...: return ModuleSpec('module', ExampleLoader()) ...: ...: def example_hook(path): ...: # some conditions here ...: return ExampleFinder() ...: ...: sys.path_hooks = [example_hook] ...: # force to use the hook ...: sys.path_importer_cache.clear() ...: ...: import module ...: moduleOut[1]: <module 'module' (<__main__.ExampleLoader object at 0x7fdb08f74b90>)>
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PLC的基本知识?plc的一些基础知识点
- 修复Windows 10更新错误的最佳方法
- 基于SpringBoot的微服务架构与K8S容器部署实践
- 防火墙基础与配置
- 萧何在汉书中属于 成也萧何败也萧何指的是西汉哪位开国功臣
- 朱元璋的郭宁莲是怎么死的 朱元璋老婆郭宁莲
- 哈尔科夫反击战的精妙之处
- 陈平和张良谁更会用计 陈平和张良谁的水平高
- 盗墓笔记里的汪家人是什么来历 盗墓笔记里的汪家人到底是什么人啊
- 这可能是网上最全的 Docker 工具集合