5.4.1. 加载器

模块加载器提供关键的加载功能:模块执行。 导入机制调用 importlib.abc.Loader.exec_module() 方法并传入一个参数来执行模块对象。 从 exec_module() 返回的任何值都将被忽略。

加载器必须满足下列要求:

  • 如果模块是一个 Python 模块(而非内置模块或动态加载的扩展),加载器应该在模块的全局命名空间 (module.__dict__) 中执行模块的代码。

  • 如果加载器无法执行指定模块,它应该引发 ImportError,不过在 exec_module() 期间引发的任何其他异常也会被传播。

在许多情况下,查找器和加载器可以是同一对象;在此情况下 find_spec() 方法将返回一个规格说明,其中加载器会被设为 self

模块加载器可以选择通过实现 create_module() 方法在加载期间创建模块对象。 它接受一个参数,即模块规格说明,并返回新的模块对象供加载期间使用。 create_module() 不需要在模块对象上设置任何属性。 如果模块返回 None,导入机制将自行创建新模块。

3.4 新版功能: 加载器的 create_module() 方法。

在 3.4 版更改: load_module() 方法被 exec_module() 所替代,导入机制会对加载的所有样板责任作出假定。

为了与现有的加载器兼容,导入机制会使用导入器的 load_module() 方法,如果它存在且导入器也未实现 exec_module()。 但是,load_module() 现已弃用,加载器应该转而实现 exec_module()

除了执行模块之外,load_module() 方法必须实现上文描述的所有样板加载功能。 所有相同的限制仍然适用,并带有一些附加规定:

  • 如果 sys.modules 中存在指定名称的模块对象,加载器必须使用已存在的模块。 (否则 importlib.reload() 将无法正确工作。) 如果该名称模块不存在于 sys.modules 中,加载器必须创建一个新的模块对象并将其加入 sys.modules

  • 在加载器执行模块代码之前,模块 必须 存在于 sys.modules 之中,以防止无限递归或多次加载。

  • 如果加载失败,加载器必须移除任何它已加入到 sys.modules 中的模块,但它必须 仅限 移除加载失败的模块,且所移除的模块应为加载器自身显式加载的。

在 3.5 版更改: 当 exec_module() 已定义但 create_module() 未定义时将引发 DeprecationWarning

在 3.6 版更改: 当 exec_module() 已定义但 create_module() 未定义时将引发 ImportError