Skip to main content

36.2. imp —访问 进口 内部

源代码: Lib/imp.py

3.4 版后已移除: imp 包正在等待弃用,赞成 importlib


此模块提供了用于实现 import 语句的机制的接口。它定义了以下常量和函数:

imp.get_magic()

返回用于识别字节编译代码文件(.pyc 文件)的魔术字符串值。 (对于每个Python版本,此值可能不同。)

3.4 版后已移除: 请改用 importlib.util.MAGIC_NUMBER

imp.get_suffixes()

返回一个3元素元组的列表,每个元组描述特定类型的模块。每个三元组具有形式 (suffix, mode, type),其中 suffix 是要附加到模块名称以形成要搜索的文件名的字符串,mode 是要传递到内置 open() 功能以打开文件的模式字符串(这可以是 'r' 对于文本文件或对于二进制文件的 'rb'),并且 type 是文件类型,其具有值 PY_SOURCEPY_COMPILEDC_EXTENSION 中的一个,如下所述。

3.3 版后已移除: 请使用在 importlib.machinery 上定义的常量。

imp.find_module(name[, path])

尝试找到模块 name。如果省略 pathNone,则搜索由 sys.path 给出的目录名称列表,但首先搜索几个特殊位置:函数尝试查找具有给定名称(C_BUILTIN)的内置模块,然后冻结模块 PY_FROZEN),在一些系统上,一些其他地方也被查找(在Windows上,它看起来在注册表中可能指向一个特定的文件)。

否则,path 必须是目录名称的列表;将搜索每个目录中具有由以上 get_suffixes() 返回的任何后缀的文件。列表中无效的名称将被忽略(但所有列表项必须是字符串)。

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

file 是位于开头的开放 file objectpathname 是找到的文件的路径名,description 是由 get_suffixes() 返回的描述所找到的模块类型的列表中包含的3元素元组。

如果模块不存在于文件中,则返回的 fileNonepathname 是空字符串,description 元组包含用于其后缀和模式的空字符串;模块类型在上面的括号中给出。如果搜索不成功,则提高 ImportError。其他异常表示参数或环境的问题。

如果模块是包,fileNonepathname 是包路径,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 中插入的 not

3.4 版后已移除: 请改用 importlib.util.module_from_spec()

imp.reload(module)

重新加载先前导入的 module。参数必须是一个模块对象,因此必须先被成功导入。如果您已使用外部编辑器编辑了模块源文件,并希望在不离开Python解释器的情况下试用新版本,这将非常有用。返回值是模块对象(与 module 参数相同)。

当执行 reload(module) 时:

  • Python模块的代码被重新编译并重新执行模块级代码,定义一组新的对象,这些对象绑定到模块字典中的名称。扩展模块的 init 功能不会第二次调用。

  • 与Python中的所有其他对象一样,旧对象只有在引用计数下降到零后才被回收。

  • 模块命名空间中的名称将更新为指向任何新的或已更改的对象。

  • 对旧对象的其他引用(例如模块外部的名称)不会被重新引用以引用新对象,并且如果需要,必须在每个命名空间中对其进行更新。

还有一些其他警告:

当模块被重新加载时,它的字典(包含模块的全局变量)被保留。名称的重定义将覆盖旧的定义,因此这通常不是问题。如果模块的新版本没有定义由旧版本定义的名称,则旧定义将保留。这个特性可以用于模块的优势,如果它维护一个全局表或缓存的对象 - 用 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.pyccpython-32 字符串来自当前的魔术标签(参见 get_tag();如果未定义 sys.implementation.cache_tag,则将引发 NotImplementedError)。通过传入 TrueFalsedebug_override,您可以覆盖系统的 __debug__ 值,导致优化的字节码。

path 不需要存在。

在 3.3 版更改: 如果 sys.implementation.cache_tagNone,则 NotImplementedError 被引发。

3.4 版后已移除: 请改用 importlib.util.cache_from_source()

在 3.5 版更改: debug_override 参数不再创建 .pyo 文件。

imp.source_from_cache(path)

给定 pathPEP 3147 文件名,返回关联的源代码文件路径。例如,如果 path/foo/bar/__pycache__/baz.cpython-32.pyc,则返回的路径将是 /foo/bar/baz.pypath 不需要存在,然而如果它不符合 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()

返回 PEP 3147 魔术标记字符串匹配此版本的Python的幻数,由 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

36.2.1. 例子

以下函数模拟了直到Python 1.4的标准导入语句(没有分层模块名称)。 (这个 implementation 不会在那个版本中工作,因为 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()