5.4. 加载

当一个模块说明被找到时,导入机制将在加载该模块时使用它(及其所包含的加载器)。 下面是导入的加载部分所发生过程的简要说明:

  1. module = None
  2. if spec.loader is not None and hasattr(spec.loader, 'create_module'):
  3. # It is assumed 'exec_module' will also be defined on the loader.
  4. module = spec.loader.create_module(spec)
  5. if module is None:
  6. module = ModuleType(spec.name)
  7. # The import-related module attributes get set here:
  8. _init_module_attrs(spec, module)
  9. if spec.loader is None:
  10. # unsupported
  11. raise ImportError
  12. if spec.origin is None and spec.submodule_search_locations is not None:
  13. # namespace package
  14. sys.modules[spec.name] = module
  15. elif not hasattr(spec.loader, 'exec_module'):
  16. module = spec.loader.load_module(spec.name)
  17. # Set __loader__ and __package__ if missing.
  18. else:
  19. sys.modules[spec.name] = module
  20. try:
  21. spec.loader.exec_module(module)
  22. except BaseException:
  23. try:
  24. del sys.modules[spec.name]
  25. except KeyError:
  26. pass
  27. raise
  28. return sys.modules[spec.name]

请注意以下细节:

  • 如果在 sys.modules 中存在指定名称的模块对象,导入操作会已经将其返回。

  • 在加载器执行模块代码之前,该模块将存在于 sys.modules 中。 这一点很关键,因为该模块代码可能(直接或间接地)导入其自身;预先将其添加到 sys.modules 可防止在最坏情况下的无限递归和最好情况下的多次加载。

  • 如果加载失败,则该模块 — 只限加载失败的模块 — 将从 sys.modules 中移除。 任何已存在于 sys.modules 缓存的模块,以及任何作为附带影响被成功加载的模块仍会保留在缓存中。 这与重新加载不同,后者会把即使加载失败的模块也保留在 sys.modules 中。

  • 在模块创建完成但还未执行之前,导入机制会设置导入相关模块属性(在上面的示例伪代码中为 “_init_module_attrs”),详情参见 后续部分

  • 模块执行是加载的关键时刻,在此期间将填充模块的命名空间。 执行会完全委托给加载器,由加载器决定要填充的内容和方式。

  • 在加载过程中创建并传递给 exec_module() 的模块并不一定就是在导入结束时返回的模块 2

在 3.4 版更改: 导入系统已经接管了加载器建立样板的责任。 这些在以前是由 importlib.abc.Loader.load_module() 方法来执行的。