31.1. imp — 访问导入内部结构 — Python 文档
31.1. 小鬼 — 访问进口内件
该模块为用于实现 import 语句的机制提供了一个接口。 它定义了以下常量和函数:
- imp.get_magic()
- 返回用于识别字节编译代码文件(
.pyc
文件)的魔法字符串值。 (对于每个 Python 版本,此值可能不同。)
- imp.get_suffixes()
- 返回 3 元素元组的列表,每个元组描述特定类型的模块。 每个三元组具有
(suffix, mode, type)
的形式,其中 suffix 是附加到模块名称以形成要搜索的文件名的字符串,mode 是要搜索的模式字符串传递给内置的 open() 函数来打开文件(对于文本文件可以是'r'
,对于二进制文件可以是'rb'
),以及 type 是文件类型,其值为 PY_SOURCE、PY_COMPILED 或 C_EXTENSION 之一,如下所述。
- imp.find_module(name[, path])
尝试找到模块 name。 如果省略 path 或
None
,则搜索由sys.path
给出的目录名称列表,但首先搜索几个特殊的地方:该函数试图找到一个内置的-in 具有给定名称的模块 (C_BUILTIN),然后是一个冻结模块 (PY_FROZEN),在某些系统上,其他一些地方也会被查看(在 Windows 上,它会在可能指向特定文件的注册表)。否则,path 必须是目录名列表; 搜索每个目录以查找具有上述 get_suffixes() 返回的任何后缀的文件。 列表中的无效名称将被静默忽略(但所有列表项都必须是字符串)。
如果搜索成功,则返回值为 3 元素元组
(file, pathname, description)
:file 是位于开头的打开文件对象,pathname 是找到的文件的路径名,description 是包含在get_suffixes() 返回的列表描述了找到的模块类型。
如果模块不存在于文件中,则返回的 file 为
None
,pathname 为空字符串,description 元组包含其后缀和模式为空字符串; 模块类型如上面括号中所示。 如果搜索不成功,则引发ImportError
。 其他异常表明参数或环境存在问题。如果模块是包,file 是
None
,pathname 是包路径,description 元组中的最后一项是 ]PKG_DIRECTORY。此函数不处理分层模块名称(包含点的名称)。 为了找到PM,即包P的子模块M,使用find_module()和load_module() 查找并加载包 P,然后使用 find_module() 并将 path 参数设置为
P.__path__
。 当 P 本身具有带点名称时,递归应用此配方。
- imp.load_module(name, file, pathname, description)
加载先前由 find_module() 找到的模块(或通过其他方式进行的搜索产生兼容结果)。 这个函数不仅仅是导入模块:如果模块已经导入,它相当于一个 reload()! name 参数表示完整的模块名称(包括包名称,如果这是包的子模块)。 file参数是打开的文件,pathname是对应的文件名; 当模块是包或未从文件加载时,这些可以分别是
None
和。 description 参数是一个元组,由 get_suffixes() 返回,描述必须加载什么样的模块。
如果加载成功,则返回值为模块对象; 否则,会引发异常(通常为
ImportError
)。重要: 调用者负责关闭 file 参数,如果它不是
None
,即使引发异常。 最好使用 try ... finally 语句来完成。
- imp.new_module(name)
- 返回一个名为 name 的新空模块对象。 这个对象是而不是插入到
sys.modules
中。
- imp.lock_held()
如果当前持有导入锁,则返回
True
,否则返回False
。 在没有线程的平台上,总是返回False
。在具有线程的平台上,执行导入的线程持有内部锁,直到导入完成。 此锁会阻止其他线程执行导入,直到原始导入完成,这反过来又可以防止其他线程在完成其导入过程中看到由原始线程构造的不完整模块对象(以及由此触发的导入,如果有的话) )。
- imp.acquire_lock()
为当前线程获取解释器的导入锁。 导入钩子应该使用这个锁来确保导入模块时的线程安全。
一旦一个线程获得了导入锁,同一个线程就可以再次获得它而不会阻塞; 线程每次获得它时都必须释放一次。
在没有线程的平台上,这个函数什么都不做。
2.3 版中的新功能。
- imp.release_lock()
释放解释器的导入锁。 在没有线程的平台上,这个函数什么都不做。
2.3 版中的新功能。
本模块中定义的以下整数常量用于指示find_module()的搜索结果。
- imp.PY_SOURCE
- 该模块是作为源文件找到的。
- imp.PY_COMPILED
- 该模块被发现为已编译的代码目标文件。
- imp.C_EXTENSION
- 该模块被发现为可动态加载的共享库。
- imp.PKG_DIRECTORY
- 该模块是作为包目录找到的。
- imp.C_BUILTIN
- 该模块被发现为内置模块。
- imp.PY_FROZEN
- 该模块被发现为冻结模块(参见 init_frozen())。
以下常量和函数已过时; 它们的功能可通过 find_module() 或 load_module() 获得。 它们保留下来是为了向后兼容:
- imp.SEARCH_ERROR
- 未使用。
- imp.init_builtin(name)
- 初始化名为 name 的内置模块,并返回其模块对象并将其存储在
sys.modules
中。 如果模块已经初始化,它会被初始化再次。 重新初始化涉及将内置模块的__dict__
从缓存模块复制到sys.modules
中模块的条目上。 如果没有名为 name 的内置模块,则返回None
。
- imp.init_frozen(name)
- 初始化名为 name 的冻结模块并返回其模块对象。 如果模块已经初始化,它会被初始化再次。 如果没有名为 name 的冻结模块,则返回
None
。 (冻结模块是用 Python 编写的模块,其编译的字节码对象被 Python 的 freeze 实用程序合并到定制的 Python 解释器中。 现在参见Tools/freeze/
。)
- imp.is_builtin(name)
- 如果有一个名为 name 的内置模块可以再次初始化,则返回
1
。 如果存在无法再次初始化的名为 name 的内置模块,则返回-1
(参见 init_builtin())。 如果没有名为 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 参数被忽略。 (注意:使用共享库高度依赖系统,并非所有系统都支持。)
- imp.load_source(name, pathname[, file])
- 加载并初始化作为 Python 源文件实现的模块并返回其模块对象。 如果模块已经初始化,它会被初始化再次。 name 参数用于创建或访问模块对象。 pathname 参数指向源文件。 file 参数是源文件,从一开始就打开以作为文本读取。 它当前必须是真实的文件对象,而不是模拟文件的用户定义类。 请注意,如果存在正确匹配的字节编译文件(带有后缀
.pyc
或.pyo
),它将被使用,而不是解析给定的源文件。
- class imp.NullImporter(path_string)
NullImporter 类型是一个 PEP 302 导入钩子,它通过找不到任何模块来处理非目录路径字符串。 使用现有目录或空字符串调用此类型会引发
ImportError
。 否则,返回 NullImporter 实例。对于不是目录且未被
sys.path_hooks
上的任何其他路径挂钩处理的任何路径条目,Python 将此类型的实例添加到sys.path_importer_cache
。 实例只有一种方法:- find_module(fullname[, path])
该方法总是返回
None
,表示找不到请求的模块。
2.5 版中的新功能。
31.1.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()
一个实现分层模块名称并包含 reload() 函数的更完整示例可以在模块 knee
中找到。 knee
模块可以在 Python 源代码分发的 Demo/imputil/
中找到。