"imp" --- 访问 import 内部对象
******************************

**源代码：** Lib/imp.py

3.4 版后已移除: "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()
