# `imp` --- 访问 import 内部对象

源代码： Lib/imp.py

从 3.4 版起不建议使用，将在 3.12 版中移除: `imp` 模块已被废弃，请改用 `importlib`。

本模块提供了一个接口，用于实现 `import` 语句的机制。这里定义了以下常量和函数：

imp.get_magic()

  返回用于识别字节编译代码文件 (`.pyc` files) 的魔术字符串值。 （该值对于各个 Python 版本可能不同。）

  自 3.4 版本弃用: 改用 `importlib.util.MAGIC_NUMBER`。

imp.get_suffixes()

  返回一个 3 元素元组的列表，每个元组描述了一个特定的模块类型。 每个三元组的形式为 `(suffix, mode, type)`，其中 suffix 是要附加到模块名称上以组成要搜索的文件名的字符串，mode 是要传给内置 `open()` 函数以打开该文件的模式字符串 (可以为针对文本文件的 `'r'` 或针对二进制文件的 `'rb'`)，而 type 是文件类型，它的值为 `PY_SOURCE`, `PY_COMPILED` 之一 `C_EXTENSION`，具体说明如下。

  自 3.3 版本弃用: 改用在 `importlib.machinery` 上定义的常量。

imp.find_module(name[, path])

  尝试找到模块 name。 如果 path 被省略或为 `None`，则会搜索 `sys.path` 给出的目录名列表，但在此前会先搜索几个特殊位置：该函数将尝试找到具有给定名称的内置模块 (`C_BUILTIN`)，然后是冻结模块 (`PY_FROZEN`)，并且在某些系统上还会查找其他几个位置（在 Windows 上，它将查看注册表，其中可能指向某一特定文件）。

  在其他情况下，path 必须是一个目录名列表；将在每个目录中搜索具有上述 `get_suffixes()` 所返回的任何后缀的文件。 列表中的无效名称将被静默地忽略（但是所有列表条目都必须为字符串）。

  如果搜索成功，返回值将是一个 3 元素元组 `(file, pathname, description)`:

  file 是一个放在最前面的已打开的 file object，pathname 是打到的文件的路径名，而 description 是一个描述所找到的模块种类的 3 元素元组，如 `get_suffixes()` 所返回的列表中包含的内容。

  如果模块为内置或冻结模块则 file 和 pathname 都将为 `None` 并且 description 元组将包含空字符串来表示其后缀和模式；模块类型按上述圆括号中所给出的内容来指明。 如果搜索未成功，则会引发 `ImportError`。 其他异常被用于指示参数或环境问题。

  如果模块是一个包，则 file 将为 `None`，pathname 将为包路径而 description 元组的最后一项将为 `PKG_DIRECTORY`。

  此函数不会处理多层级的模块名称（包含点号的名称）。 为了找到 P.M，也就是 P 包的的子模块 M，请使用 `find_module()` 和 `load_module()` 来找到并载入 P 包，然后使用 `find_module()` 并将 path 参数设为 `P.__path__`。 当 P 本身也具有带点号的名称时，请递归地应用此步骤。

  自 3.3 版本弃用: 请改用 `importlib.util.find_spec()` 除非需要兼容 Python 3.3，对于后一种情况请使用 `importlib.find_loader()`。 要查看对于前一种情况的示例用法，请参阅 `importlib` 文档的 例子 小节。

imp.load_module(name, file, pathname, description)

  加载之前由 `find_module()` 所找到的模块（或由其他方式执行搜索所产生的兼容的结果）。 此函数所做的不只是导入模块：如果模块已经被导入，它将重新加载此模块！ name 参数指明完整的模块名称（包括包名，如果它是一个包的子模块的话）。 file 参数是一个打开的文件，而 pathname 是相应的文件名；当模块是一个包或者不是从文档加载时，它们可以分别为 `None` 和 `''`。 description 参数是一个元组，如 `get_suffixes()` 将返回的内容一样，描述了必须加载什么样的模块。

  如果加载成功，则返回值为相应的模块对象；否则，将引发一个异常 (通常为 `ImportError`)。

  重要: 调用方需负责关闭 file 参数，如果它不为 `None` 的话，即使是在有异常被引发时。 这最好是使用 `try` ... `finally` 语句来实现。

  自 3.3 版本弃用: 如果之前是与 `imp.find_module()` 一起使用则可考虑使用 `importlib.import_module()`，在其他情况下请使用你选择的 `imp.find_module()` 替代品所返回的加载器。 如果你直接附带文件路径参数调用 `imp.load_module()` 和相关函数则请使用 `importlib.util.spec_from_file_location()` 和 `importlib.util.module_from_spec()` 的组合。 参见 `importlib` 文档的 例子 小节来了解各种方式的细节。

imp.new_module(name)

  返回一个新的名为 name 的空模块对象。 此对象 不会 被插入到 `sys.modules` 中。

  自 3.4 版本弃用: 请改用 `importlib.util.module_from_spec()`。

imp.reload(module)

  重新加载之前导入的 module。 该参数必须是一个模块对象，因此它之前必须已经被成功导入了。 这在当你已使用外部编辑器编辑过模块源代码文件并想在不退出 Python 解释器的情况下尝试新版本时会很有用处。 返回值为模块对象（与 module 参数所指向的相同）。

  当 `reload(module)` 被执行时:

  - Python 模块的代码会被重新编译并且模块层级的代码将重新执行，定义一个新的绑定到模块字典中的名称的对象集合。 扩展模块的 `init` 函数不会被重复调用。

  - 与Python中的所有的其它对象一样，旧的对象只有在它们的引用计数为0之后才会被回收。

  - 模块命名空间中的名称重新指向任何新的或更改后的对象。

  - 其他旧对象的引用（例如那个模块的外部名称）不会被重新绑定到引用的新对象的，并且如果有需要，必须在出现的每个命名空间中进行更新。

  有一些其他注意事项：

  当一个模块被重新加载的时候，它的字典（包含了那个模块的全区变量）会被保留。名称的重新定义会覆盖旧的定义，所以通常来说这不是问题。如果一个新模块没有定义在旧版本模块中定义的名称，则将保留旧版本中的定义。这一特性可用于作为那个模块的优点，如果它维护一个全局表或者对象的缓存 —— 使用 `try` 语句，就可以测试表的存在并且跳过它的初始化，如果有需要的话:

      try:
          cache
      except NameError:
          cache = {}

  重新加载内置或动态加载的模块是合法操作但通常不是很有用处，除非是 `sys`, `__main__` 和 `builtins`。 但是在许多情况下，扩展模块并不是被设计为可被多次初始化的，并可能在重新加载时以任意方式失败。

  如果一个模块使用 `from` ... `import` ... 导入来自另一个模块的对象，则为另一个模块调用 `reload()` 并不会重新定义从其中导入的对象 --- 绕过此问题的一种方式是重新执行 `from` 语句，另一种方式是使用 `import` 和限定名称 (module.*name*) 来代替。

  如果一个模块创建一个类的实例，重新加载定义那个类的模块不影响那些实例的方法定义———它们继续使用旧类中的定义。对于子类来说同样是正确的。

  在 3.3 版本发生变更: 依赖于 `__name__` 和 `__loader__` 而不仅是 `__name__` 同时定义在被重新加载的模块上。

  自 3.4 版本弃用: 使用 `importlib.reload()` 来代替。

下列函数可以方便地处理 PEP 3147 字节编译的文件路径。

在 3.2 版本加入.

imp.cache_from_source(path, debug_override=None)

  返回与源 PEP 3147 定义的 path 相关联的已编译字节码文件的路径。 举例来说，如果 path 为 `/foo/bar/baz.py` 则 Python 3.2 中的返回值将是 `/foo/bar/__pycache__/baz.cpython-32.pyc`。 字符串 `cpython-32` 来自于当前的魔术标签 (参见 `get_tag()`; 如果 `sys.implementation.cache_tag` 未定义则将引发 `NotImplementedError`)。 通过为 debug_override 传入 `True` 或 `False` 你可以覆盖系统设置的 `__debug__` 值，以生成优化的字节码。

  path 不必存在。

  在 3.3 版本发生变更: 如果 `sys.implementation.cache_tag` 为 `None`，则会引发 `NotImplementedError`。

  自 3.4 版本弃用: 使用 `importlib.util.cache_from_source()` 来代替。

  在 3.5 版本发生变更: debug_override 形参不会再创建 `.pyo` 文件。

imp.source_from_cache(path)

  根据给定的 PEP 3147 文件名的 path，返回相关联的源代码文件路径。 举例来说，如果 path 为 `/foo/bar/__pycache__/baz.cpython-32.pyc` 则返回的路径将是 `/foo/bar/baz.py`。 path 不必已存在，但是如果它未遵循 PEP 3147 格式，则会引发 `ValueError`。 如果未定义 `sys.implementation.cache_tag`，则会引发 `NotImplementedError`。

  在 3.3 版本发生变更: 当未定义 `sys.implementation.cache_tag` 时将引发 `NotImplementedError`。

  自 3.4 版本弃用: 使用 `importlib.util.source_from_cache()` 来代替。

imp.get_tag()

  返回与此 Python 版本魔数相匹配的 PEP 3147 魔术标签字符串，如 `get_magic()` 所返回的。

  自 3.4 版本弃用: 从 Python 3.3 开始直接使用 `sys.implementation.cache_tag`。

以下函数可以帮助与导入系统的内部锁定机制进行交互。 导入的锁定语义是一个可能在不同发布版之间发生改变的实现细节。 但是，Python 会确保循环导入操作不会出现任何死锁。

imp.lock_held()

  如果当前持有全局导入锁则返回 `True`，否则返回 `False`。 在没有线程的系统平台上，将总是返回 `False`。

  在有线程的平台上，执行导入的线程首先会持有一个全局导入锁，然后为导入其余部分设置模块专属锁。 这将阻止其他线程导入相同的模块直到原始导入完成，防止其他线程看到由原始线程构建的不完整的模块对象。 循环导入是个例外情况，它在构造上就必须在某一时刻暴露不完整的模块对象。

  在 3.3 版本发生变更: 锁定方案在大多数情况下都已改为按模块锁定。 对于某些关键任务会保留一个全局导入锁，比如初始化每个模块的锁。

  自 3.4 版本弃用.

imp.acquire_lock()

  为当前线程获取解释器的全局导入锁。 这个锁应当由导入钩子来使用以确保导入模块时的线程安全。

  一旦某个线程获取了导入锁，同一个线程可以再次获取它而不会阻塞；该线程每次获得它都必须再释放它一次。

  在没有线程的平台上，此函数将不做任何操作。

  在 3.3 版本发生变更: 锁定方案在大多数情况下都已改为按模块锁定。 对于某些关键任务会保留一个全局导入锁，比如初始化每个模块的锁。

  自 3.4 版本弃用.

imp.release_lock()

  释放解释器的全局导入锁。 在没有线程的平台上，此函数将不做任何操作。

  在 3.3 版本发生变更: 锁定方案在大多数情况下都已改为按模块锁定。 对于某些关键任务会保留一个全局导入锁，比如初始化每个模块的锁。

  自 3.4 版本弃用.

以下是在本模块中定义的具有整数值的常量，用来表示 `find_module()` 的搜索结果。

imp.PY_SOURCE

  模块作为一个源文件被发现。

  自 3.3 版本弃用.

imp.PY_COMPILED

  模块作为一个已编译代码对象文件被发现。

  自 3.3 版本弃用.

imp.C_EXTENSION

  模块作为动态可加载共享库被发现。

  自 3.3 版本弃用.

imp.PKG_DIRECTORY

  模块作为一个包目录被发现。

  自 3.3 版本弃用.

imp.C_BUILTIN

  模块作为一个内置模块被发现。

  自 3.3 版本弃用.

imp.PY_FROZEN

  模块作为一个冻结模块被发现。

  自 3.3 版本弃用.

class imp.NullImporter(path_string)

  `NullImporter` 类型是一个在无法找到任何模块时处理非目录路径字符串 PEP 302 导入钩子。 调用此类型时传入一个现有目录或空字符串将引发 `ImportError`。 在其他情况下，将返回一个 `NullImporter` 实例。

  这些实例只有一个方法:

  find_module(fullname[, path])

    此方法总是返回 `None`，表示所请求的模块无法找到。

  在 3.3 版本发生变更: 将把 `None` 插入到 `sys.path_importer_cache` 而不是 `NullImporter` 的实例。

  自 3.4 版本弃用: 改为将 `None` 插入到 `sys.path_importer_cache`。

## 例子

以下函数模拟了 Python 1.4 及之前版本的标准导入语句（没有多层级的模块名称）。 （这个 实现 不可用于那些版本，因为 `find_module()` 已经被扩展而 `load_module()` 在 1.4 中已被添加。）

    import imp
    import sys

    def __import__(name, globals=None, locals=None, fromlist=None):
        # Fast path: see if the module has already been imported.
        try:
            return sys.modules[name]
        except KeyError:
            pass

        # If any of the following calls raises an exception,
        # there's a problem we can't handle -- let the caller handle it.

        fp, pathname, description = imp.find_module(name)

        try:
            return imp.load_module(name, fp, pathname, description)
        finally:
            # Since we may exit via an exception, close fp explicitly.
            if fp:
                fp.close()