31.1. imp —访问导入内部

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

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

    • 返回一个三元素 Tuples 的列表,每个 Tuples 描述一种特定类型的模块。每个三 Tuples 的格式均为(suffix, mode, type),其中* suffix 是要添加到模块名称后的字符串,以形成要搜索的文件名, mode 是要传递给内置open()函数以打开文件的模式字符串(对于文本文件,它可以是'r';对于二进制文件,它可以是'rb'),而 type *是文件类型,其值如下所述PY_SOURCEPY_COMPILEDC_EXTENSION之一。
  • 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 是位于开头的打开的文件对象, pathname 是找到的文件的路径名, description *是 3 元素 Tuples,包含在get_suffixes()返回的描述所找到模块类型的列表中。

如果模块不在文件中,则返回的* file None pathname 为空字符串,并且 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 *本身具有点名时,请递归应用此配方。

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

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

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

  • imp. new_module(* name *)

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

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

在具有线程的平台上,执行导入的线程持有内部锁,直到导入完成。此锁将阻止其他线程进行导入,直到原始导入完成为止,这又防止其他线程在完成其导入过程中看到由原始线程构造的不完整的模块对象(以及由导入触发的导入,如果有的话) )。

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

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

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

2.3 版的新Function。

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

2.3 版的新Function。

在此模块中定义的以下具有整数值的常量用于指示find_module()的搜索结果。

  • imp. PY_SOURCE

    • 找到该模块作为源文件。
  • imp. PY_COMPILED

    • 找到该模块作为已编译的代码目标文件。
  • imp. C_EXTENSION

    • 发现该模块为可动态加载的共享库。
  • imp. PKG_DIRECTORY

    • 找到该模块作为软件包目录。
  • imp. C_BUILTIN

    • 发现该模块为内置模块。
  • imp. PY_FROZEN

以下常量和函数已过时;它们的Function可passfind_module()load_module()获得。保留它们是为了向后兼容:

  • imp. SEARCH_ERROR

    • Unused.
  • imp. init_builtin(* name *)

    • 初始化名为* name 的内置模块,并返回其模块对象并将其存储在sys.modules中。如果模块已经被初始化,它将再次被初始化。重新初始化涉及passsys.modules中的模块条目从缓存的模块复制内置模块的__dict__。如果没有名为 name *的内置模块,则返回None
  • imp. init_frozen(* name *)

    • 初始化名为* name 的冻结模块并返回其模块对象。如果模块已经被初始化,它将再次被初始化。如果没有名为 name *的冻结模块,则返回None。 (冻结模块是用 Python 编写的模块,其编译后的字节码对象已pass Python 的 freeze Util 并入自定义的 Python 解释器中.有关详细信息,请参阅Tools/freeze/.)
  • imp. is_builtin(* name *)

    • 如果有一个名为* name 的内置模块可以再次初始化,则返回1。如果有一个名为 name 的内置模块无法再次初始化(请参见init_builtin()),则返回-1。如果没有名为 name *的内置模块,则返回0
  • imp. is_frozen(* name *)

    • 如果存在称为* name *的冻结模块(请参见init_frozen()),则返回True;如果没有这样的模块,则返回False
  • imp. load_compiled(* name pathname * [,* file *])

    • 加载并初始化一个实现为字节编译代码文件的模块,然后返回其模块对象。如果模块已经被初始化,它将再次被初始化。 * name *参数用于创建或访问模块对象。 * pathname *参数指向字节编译的代码文件。 * file *参数是字节编译的代码文件,从头开始以二进制模式读取。当前,它必须是真实的文件对象,而不是用户定义的模拟文件的类。
  • imp. load_dynamic(* name pathname * [,* file *])
    • 加载并初始化实现为可动态加载的共享库的模块,然后返回其模块对象。如果模块已经被初始化,它将再次被初始化。重新初始化涉及将模块的缓存实例的__dict__属性复制到sys.modules中缓存的模块中使用的值上。 * pathname *参数必须指向共享库。 * name 参数用于构造初始化函数的名称:在共享库中调用名为initname()的外部 C 函数。可选的 file *参数将被忽略。 (注意:使用共享库在很大程度上取决于系统,并且并非所有系统都支持它.)

CPython 实现细节: 导入内部结构pass文件名标识扩展模块,因此执行foo = load_dynamic("foo", "mod.so")bar = load_dynamic("bar", "mod.so")将导致 foo 和 bar 引用同一模块,而不管mod.so是否导出initbar函数。在支持它们的系统上,符号链接可用于从同一共享库中导入多个模块,因为对该模块的每次引用都将使用不同的文件名。

  • imp. load_source(* name pathname * [,* file *])

    • 加载并初始化实现为 Python 源文件的模块,然后返回其模块对象。如果模块已经被初始化,它将再次被初始化。 * name *参数用于创建或访问模块对象。 * pathname *参数指向源文件。 * file *参数是源文件,从头开始以文本形式阅读。当前,它必须是真实的文件对象,而不是用户定义的模拟文件的类。请注意,如果存在一个正确匹配的字节编译文件(后缀.pyc.pyo),则将使用该文件代替解析给定的源文件。
    • class * imp. NullImporter(* path_string *)
    • NullImporter类型是 PEP 302导入钩子,它pass找不到任何模块来处理非目录路径字符串。用现有目录或空字符串调用此类型会引发ImportError。否则,将返回一个NullImporter实例。

对于不是目录并且未被sys.path_hooks上的任何其他路径钩子处理的任何路径条目,Python 会将这种类型的实例添加到sys.path_importer_cache。实例只有一种方法:

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

2.5 版的新Function。

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

在模块knee中可以找到一个更完整的示例,该示例实现了分层模块名称并包括reload()函数。 knee模块可以在 Python 源代码发行版的Demo/imputil/中找到。