36.2. imp - 访问import内部

源代码: Lib/imp.py

自版本3.4后已弃用: imp包正在等待废弃,换成importlib

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

imp.get_magic()

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

自版本3.4后已弃用:改用importlib.util.MAGIC_NUMBER

imp.get_suffixes()

返回一个3元素元组的列表,每个元组描述特定类型的模块。每个三元组具有(后缀, 模式, 类型)的形式,其中是要附加到模块名称以形成要搜索的文件名的字符串,模式是要传递到内建open()函数的模式字符串,文件(对于文本文件可以是'r',对于二进制文件可以是'rb'),类型是文件类型,以下描述的值PY_SOURCEPY_COMPILEDC_EXTENSION中的一个。

自版本3.3后已弃用:改用importlib.machinery中定义的常量。

imp.find_module(name[, path])

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

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

如果搜索成功,返回值为3元素元组(文件, 路径名, 描述)

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

如果模块不在文件中,返回的文件None路径名为空字符串,/ t4> tuple包含其后缀和模式的空字符串;模块类型如上面括号中所示。如果搜索不成功,则会引发ImportError其他异常表示参数或环境的问题。

如果模块是包,文件None路径名是包路径和描述 t4中的最后一个项目> tuple是PKG_DIRECTORY

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

自版本3.3后已弃用:除非需要Python 3.3兼容性,否则使用importlib.util.find_spec(),在这种情况下,请使用importlib.find_loader()

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

加载以前由find_module()发现的模块(或通过其他方式进行的搜索,产生兼容的结果)。此函数不仅仅导入模块:如果模块已经导入,它将重新加载模块!name参数指示完整的模块名称(包括程序包名称,如果它是程序包的子模块)。文件参数是打开的文件,路径名是相应的文件名;当模块是包或者没有从文件加载时,这些可以分别是None''描述参数是一个元组,由get_suffixes()返回,描述必须加载什么样的模块。

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

重要提示:如果不是None,即使发生异常,调用者也负责关闭文件参数。最好使用try ... finally语句。

从版本3.3开始弃用:如果之前与imp.find_module()结合使用,则考虑使用importlib.import_module(),否则使用加载器由您为imp.find_module()选择的替换返回。如果您直接调用imp.load_module()和相关函数,请使用importlib.machinery中的类,例如importlib.machinery.SourceFileLoader(name, path).load_module()

imp.new_module(name)

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

自版本3.4后已弃用:改用types.ModuleType

imp.reload(module)

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

当执行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/foo/bar/baz.py,则返回值为/foo/bar/__pycache__/baz.cpython-32.pyc for Python 3.2。cpython-32字符串来自当前的魔术标签(参见get_tag();如果没有定义sys.implementation.cache_tag,则NotImplementedError会被提出)。通过为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文件名,返回关联的源代码文件路径。例如,如果路径/foo/bar/__pycache__/baz.cpython-32.pyc,则返回的路径为/foo/bar/baz.pypath不需要存在,但如果它不符合 PEP 3147格式,则会引发ValueError如果未定义sys.implementation.cache_tag,则会引发NotImplementedError

在未定义sys.implementation.cache_tag时,在版本3.3中更改了提升NotImplementedError

自从版本3.4开始弃用:改为使用importlib.util.source_from_cache()

imp.get_tag()

返回与get_magic()返回的Python的幻数的版本匹配的 PEP 3147魔术标记字符串。

自版本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. 实例¶ T0>

以下函数模拟了直到Python 1.4的标准import语句(没有分层模块名称)。(由于find_module()已经扩展,并且在1.4中添加了load_module(),因此此实现

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()