imp --访问 import 内构件

源代码: Lib/imp.py

3.4 版后已移除: 这个 imp 模块已弃用,取而代之的是 importlib .


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

imp.get_magic()

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

3.4 版后已移除: 使用 importlib.util.MAGIC_NUMBER 相反。

imp.get_suffixes()

返回三元素元组的列表,每个元组描述特定类型的模块。每三个都有形式 (suffix, mode, type) 在哪里 后缀 是要附加到模块名称以形成要搜索的文件名的字符串, mode 是要传递给内置 open() 函数打开文件(可以 'r' 对于文本文件或 'rb' 对于二进制文件),以及 type 是文件类型,它具有以下值之一 PY_SOURCEPY_COMPILEDC_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 在开始的时候, 路径名 是否找到文件的路径名,以及 description 是包含在由返回的列表中的3元素元组 get_suffixes() 描述找到的模块类型。

如果模块是内置的或冻结的,则 file路径名 都是 None 以及 描述 元组的后缀和模式包含空字符串;模块类型如上面括号中所示。如果搜索失败, ImportError 提高了。其他异常表示参数或环境有问题。

如果模块是一个包, fileNone路径名 是包路径和 description 元组是 PKG_DIRECTORY .

此函数不处理分层模块名称(包含点的名称)。为了找到 P.M 也就是说,子模块 M 封装的 P 使用 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 参数是打开的文件,并且 路径名 是相应的文件名;可以是 None'' 当模块是包或不是从文件加载时。这个 description 参数是一个元组,将由返回 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 各种方法的详细说明文件。

imp.new_module(name)

返回名为 name . 这个对象是 not 插入 sys.modules .

3.4 版后已移除: 使用 importlib.util.module_from_spec() 相反。

imp.reload(module)

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

什么时候? reload(module) 执行:

  • python模块的代码被重新编译,模块级代码被重新执行,定义了一组绑定到模块字典中名称的新对象。这个 init 扩展模块的函数没有第二次调用。

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

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

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

还有许多其他注意事项:

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

try:
    cache
except NameError:
    cache = {}

虽然重新加载内置或动态加载的模块通常不是很有用,但是 sys__main__builtins . 然而,在许多情况下,扩展模块的设计不能被多次初始化,并且在重新加载时可能以任意方式失败。

如果某个模块使用 fromimport ……调用 reload() 因为另一个模块没有重新定义从它导入的对象——一种方法是重新执行 from 声明,另一个是使用 import 和限定名( 模块 . 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 返回值为 /foo/bar/__pycache__/baz.cpython-32.pyc 对于python 3.2。这个 cpython-32 字符串来自当前的magic标记(请参见 get_tag() 如果 sys.implementation.cache_tag 则未定义 NotImplementedError 将被引发)。通过在 TrueFalse 对于 debug_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)

鉴于 path 到A PEP 3147 文件名,返回关联的源代码文件路径。例如,如果 path/foo/bar/__pycache__/baz.cpython-32.pyc 返回的路径将是 /foo/bar/baz.py . path 但是,如果它不符合 PEP 3147 格式,A ValueError 提高了。如果 sys.implementation.cache_tag 未定义, NotImplementedError 提高了。

在 3.3 版更改: 提高 NotImplementedError 什么时候? sys.implementation.cache_tag 未定义。

3.4 版后已移除: 使用 importlib.util.source_from_cache() 相反。

imp.get_tag()

返回 PEP 3147 与此版本的python的magic编号匹配的magic标记字符串,由返回 get_magic() .

3.4 版后已移除: 使用 sys.implementation.cache_tag 直接从python 3.3开始。

以下功能有助于与导入系统的内部锁定机制进行交互。导入的锁定语义是一个实现细节,可能随发布而变化。但是,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 . 否则,A 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()