imp
—— 由代码内部访问 import 。¶
源代码: Lib/imp.py
本模块提供了一个接口,用于实现 import
语句的机制。这里定义了以下常量和函数:
- imp.get_magic()¶
返回用于识别字节编译代码文件 (
.pyc
files) 的魔术字符串值。 (该值对于各个 Python 版本可能不同。)3.4 版后已移除: 改用
importlib.util.MAGIC_NUMBER
。
- imp.get_suffixes()¶
返回一个 3 元素元组的列表,每个元组描述了一个特定的模块类型。 每个三元组的形式为
(suffix, mode, type)
,其中 suffix 是要附加到模块名称上以组成要搜索的文件名的字符串,mode 是要传给内置open()
函数以打开该文件的模式字符串 (可以为针对文本文件的'r'
或针对二进制文件的'rb'
),而 type 是文件类型,它的值为PY_SOURCE
,PY_COMPILED
之一C_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,pathname 是打到的文件的路径名,而 description 是一个描述所找到的模块种类的 3 元素元组,如
get_suffixes()
所返回的列表中包含的内容。如果模块为内置或冻结模块则 file 和 pathname 都将为
None
并且 description 元组将包含空字符串来表示其后缀和模式;模块类型按上述圆括号中所给出的内容来指明。 如果搜索未成功,则会引发ImportError
。 其他异常被用于指示参数或环境问题。如果模块是一个包,则 file 将为
None
,pathname 将为包路径而 description 元组的最后一项将为PKG_DIRECTORY
。此函数不会处理多层级的模块名称(包含点号的名称)。 为了找到 P.M,也就是 P 包的的子模块 M,请使用
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 参数是一个打开的文件,而 pathname 是相应的文件名;当模块是一个包或者不是从文档加载时,它们可以分别为None
和''
。 description 参数是一个元组,如get_suffixes()
将返回的内容一样,描述了必须加载什么样的模块。如果加载成功,则返回值为相应的模块对象;否则,将引发一个异常 (通常为
ImportError
)。重要: 调用方需负责关闭 file 参数,如果它不为
None
的话,即使是在有异常被引发时。 这最好是使用try
...finally
语句来实现。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 的空模块对象。 此对象 不会 被插入到
sys.modules
中。3.4 版后已移除: 请改用
importlib.util.module_from_spec()
。
- imp.reload(module)¶
重新加载之前导入的 module。 该参数必须是一个模块对象,因此它之前必须已经被成功导入了。 这在当你已使用外部编辑器编辑过模块源代码文件并想在不退出 Python 解释器的情况下尝试新版本时会很有用处。 返回值为模块对象(与 module 参数所指向的相同)。
当
reload(module)
被执行时:Python 模块的代码会被重新编译并且模块层级的代码将重新执行,定义一个新的绑定到模块字典中的名称的对象集合。 扩展模块的
init
函数不会被重复调用。与Python中的所有的其它对象一样,旧的对象只有在它们的引用计数为0之后才会被回收。
模块命名空间中的名称重新指向任何新的或更改后的对象。
其他旧对象的引用(例如那个模块的外部名称)不会被重新绑定到引用的新对象的,并且如果有需要,必须在出现的每个命名空间中进行更新。
有一些其他注意事项:
当一个模块被重新加载的时候,它的字典(包含了那个模块的全区变量)会被保留。名称的重新定义会覆盖旧的定义,所以通常来说这不是问题。如果一个新模块没有定义在旧版本模块中定义的名称,则将保留旧版本中的定义。这一特性可用于作为那个模块的优点,如果它维护一个全局表或者对象的缓存 —— 使用
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 相关联的已编译字节码文件的路径。 举例来说,如果 path 为
/foo/bar/baz.py
则 Python 3.2 中的返回值将是/foo/bar/__pycache__/baz.cpython-32.pyc
。 字符串cpython-32
来自于当前的魔术标签 (参见get_tag()
; 如果sys.implementation.cache_tag
未定义则将引发NotImplementedError
)。 通过为 debug_override 传入True
或False
你可以覆盖系统设置的__debug__
值,以生成优化的字节码。path 不必存在。
在 3.3 版更改: 如果
sys.implementation.cache_tag
为None
,则会引发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()¶
返回与此 Python 版本魔数相匹配的 PEP 3147 魔术标签字符串,如
get_magic()
所返回的。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
。
例子¶
以下函数模拟了 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()