imp —访问导入内部

源代码: Lib/imp.py

自版本 3.4 起不推荐使用:不推荐使用imp模块,而推荐使用importlib


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

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

从 3.4 版开始不推荐使用:改为使用importlib.util.MAGIC_NUMBER

  • imp. get_suffixes ( )
    • 返回一个三元素 Tuples 的列表,每个 Tuples 描述一种特定类型的模块。每个三 Tuples 的格式均为(suffix, mode, type),其中* suffix 是要添加到模块名称后的字符串,以形成要搜索的文件名, mode 是要传递给内置open()函数以打开文件的模式字符串(对于文本文件,它可以是'r';对于二进制文件,它可以是'rb'),而 type *是文件类型,其值如下所述PY_SOURCEPY_COMPILEDC_EXTENSION之一。

从版本 3.3 开始不推荐使用:而是使用在importlib.machinery上定义的常量。

  • imp. find_module(* name * [,* path *])
    • try找到模块* name 。如果Ellipsis path *或None,则搜索sys.path给定的目录名称列表,但首先搜索几个特殊位置:该函数try查找具有给定名称(C_BUILTIN)的内置模块,然后冻结模块(PY_FROZEN),并且在某些系统上也会查找其他位置(在 Windows 上,它会在注册表中查找可能指向特定文件的位置)。

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

如果搜索成功,则返回值为 3 元素 Tuples(file, pathname, description)

  • file 是一个位于开头的开放file object pathname 是找到的文件的路径名, description *是一个 3 元素 Tuples,包含在get_suffixes()返回的列表中,描述了找到的模块的类型。

如果模块是内置的或冻结的,则* file pathname 均为None,并且 description *Tuples 的后缀和模式包含空字符串;模块类型如上括号中所示。如果搜索失败,则引发ImportError。其他异常表明参数或环境存在问题。

如果模块是包,则* file None pathname 是包路径,并且 description *Tuples 中的最后一项是PKG_DIRECTORY

此函数不处理分层模块名称(包含点的名称)。为了找到* P.M ,即包 P 的子模块 M ,请使用find_module()load_module()查找并加载包 P ,然后将find_module() path 参数设置为P.__path__。当 P *本身具有点名时,请递归应用此配方。

从版本 3.3 开始不推荐使用:除非需要 Python 3.3 兼容性,否则请使用importlib.util.find_spec(),在这种情况下请使用importlib.find_loader()。有关前一种情况的用法示例,请参见importlib文档的Examples部分。

  • imp. load_module(* name file pathname description *)
    • 加载先前由find_module()找到的模块(或pass其他进行的搜索产生兼容的结果)。该Function不仅仅可以导入模块:如果模块已经被导入,它将重新加载模块! * name *参数指示完整的模块名称(包括软件包名称,如果这是软件包的子模块)。 * file 参数是一个打开的文件, pathname *是相应的文件名;当模块是软件包或未从文件加载时,它们分别可以是None''。 * description *参数是一个 Tuples,由get_suffixes()返回,描述了必须加载哪种模块。

如果加载成功,则返回值为模块对象。否则,将引发异常(通常为ImportError)。

重要: 调用者负责关闭* file *参数,即使它不是None,即使引发异常也是如此。最好使用tryfinally语句完成此操作。

从版本 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文档的Examples部分。

  • imp. new_module(* name *)
    • 返回一个名为* name *的新的空模块对象。 将此对象插入sys.modules

从 3.4 版开始不推荐使用:改为使用importlib.util.module_from_spec()

  • imp. reload(* module *)
    • 重新加载先前导入的* module 。参数必须是模块对象,因此它必须已经成功导入。如果您已使用外部编辑器编辑了模块源文件,并且想在不离开 Python 解释器的情况下try新版本,则这将非常有用。返回值是模块对象(与 module *参数相同)。

当执行reload(module)时:

  • 重新编译 Python 模块的代码并重新执行模块级代码,从而定义了一组新对象,这些对象绑定到模块字典中的名称。扩展模块的initFunction不再被调用。

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

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

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

还有其他一些警告:

重新加载模块时,将保留其字典(包含模块的全局变量)。名称的重新定义将覆盖旧的定义,因此这通常不是问题。如果模块的新版本未定义旧版本定义的名称,则保留旧定义。如果此Function维护模块的全局表或对象缓存,则可以利用该模块的优势-使用try语句,它可以测试表的存在并在需要时跳过其初始化:

try:
    cache
except NameError:
    cache = {}

尽管sysmainbuiltins除外,但重新加载内置或动态加载的模块通常不是很有用,但这是合法的。但是,在许多情况下,扩展模块的设计不会被初始化一次以上,并且在重新加载时可能会以任意方式失败。

如果一个模块使用fromimport…从另一个模块导入对象,则对另一个模块调用reload()不会重新定义从其导入的对象-一种解决方法是重新执行from语句,另一种方法是使用import和限定名称(* module . name *)代替。

如果模块实例化一个类的实例,则重新加载定义该类的模块不会影响实例的方法定义-它们将 continue 使用旧的类定义。派生类也是如此。

在版本 3.3 中进行了更改:依赖于在重新加载的模块上定义的__name____loader__,而不仅仅是__name__

从 3.4 版开始不推荐使用:改为使用importlib.reload()

以下Function为处理 PEP 3147个字节编译的文件路径提供了便利。

3.2 版中的新Function。

  • 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)。pass为_debug_override *传递TrueFalse,可以覆盖__debug__的系统值,从而优化字节码。

路径不需要存在。

在版本 3.3 中更改:如果sys.implementation.cache_tagNone,则引发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 ( )
    • 返回get_magic()返回的 PEP 3147魔术标签字符串,该字符串与该版本的 Python 魔术数匹配。

从 3.4 版开始不推荐使用:从 python 3.3 开始直接使用sys.implementation.cache_tag

以下Function有助于与导入系统的内部锁定机制进行交互。导入的锁定语义是一个实现细节,每个发行版可能会有所不同。但是,Python 确保循环导入可以正常工作而不会出现任何死锁。

  • imp. lock_held ( )
    • 如果当前持有全局导入锁,则返回True,否则返回False。在没有线程的平台上,始终返回False

在具有线程的平台上,执行导入的线程首先拥有全局导入锁,然后为其余的导入设置每个模块的锁。这将阻止其他线程导入同一模块,直到原始导入完成为止,从而防止其他线程看到由原始线程构造的不完整的模块对象。循环导入有一个 exception,循环导入必须pass构造在某个点公开不完整的模块对象。

在版本 3.3 中进行了更改:在大多数情况下,锁定方案已更改为按模块锁定。对于某些关键任务,将保留全局导入锁,例如初始化每个模块的锁。

自 3.4 版起不推荐使用。

  • imp. acquire_lock ( )
    • 获取当前线程的解释器的全局导入锁。导入钩子应使用此锁,以确保导入模块时的线程安全。

一旦线程获取了导入锁,同一线程就可以再次获取它而不会阻塞;线程必须在每次获取它后释放一次。

在没有线程的平台上,此Function不执行任何操作。

在版本 3.3 中进行了更改:在大多数情况下,锁定方案已更改为按模块锁定。对于某些关键任务,将保留全局导入锁,例如初始化每个模块的锁。

自 3.4 版起不推荐使用。

  • imp. release_lock ( )
    • 释放解释器的全局导入锁。在没有线程的平台上,此Function不执行任何操作。

在版本 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导入钩子,它pass找不到任何模块来处理非目录路径字符串。用现有目录或空字符串调用此类型会引发ImportError。否则,将返回一个NullImporter实例。

实例只有一种方法:

  • find_module((全名 [,路径])
    • 此方法始终返回None,指示找不到请求的模块。

在版本 3.3 中进行了更改:None而不是NullImporter的实例被插入sys.path_importer_cache

从 3.4 版开始不推荐使用:将None插入sys.path_importer_cache

Examples

以下函数模拟 Python 1.4 之前的标准 import 语句(无分层模块名称)。 (此实现在该版本中不起作用,因为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()