imp —— 由代码内部访问 import 。
源代码: Lib/imp.py
从版本 3.4 开始标记为过时,将在版本 3.12 中移除。: imp 模块已被废弃,请改用 importlib。
本模块提供了一个接口,用于实现 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()