20.2. importlib — python 的模块载入机制 | 模块和扩展 |《python 3 标准库实例教程》| python 技术论坛-金年会app官方网
目的: importlib 模块公开了 python 中 import 语句的实现
importlib
模块包含实现 python 导入机制的函数,用于在包和模块中加载代码。 它是动态导入模块的一个访问点,在编写代码时需要导入的模块名称未知的情况下很有用(例如,对于应用程序的插件或扩展)。
示例包
本节的示例使用了一个包
称为 example
,包含有 __init__.py
。
example/init.py
print('importing example package')
这个包还包含 submodule.py
。
example/submodule.py
print('importing submodule')
导入包或模块时,请注意示例中 print()
调用输出的文本。
模块类型
python 支持多种样式的模块。 打开模块并将其添加到命名空间时,每个模块都需要自己处理,并且格式的支持因平台而异。 例如,在 microsoft windows 下,共享库是从扩展名为 .dll
或 .pyd
的文件加载而不是 .so
。 当使用解释器的调试版本而不是正常版本构建时,c 模块的扩展也可能会发生变化,因为它们也可以进行包含的调试信息编译。如果 c 扩展库或其他模块未按预期加载,请使用 importlib.machinery
中定义的常量来查找当前平台支持的类型以及加载它们的参数。
importlib_suffixes.py
import importlib.machinery
suffixes = [
('source:', importlib.machinery.source_suffixes),
('debug:',
importlib.machinery.debug_bytecode_suffixes),
('optimized:',
importlib.machinery.optimized_bytecode_suffixes),
('bytecode:', importlib.machinery.bytecode_suffixes),
('extension:', importlib.machinery.extension_suffixes),
]
def main():
tmpl = '{:<10} {}'
for name, value in suffixes:
print(tmpl.format(name, value))
if __name__ == '__main__':
main()
返回值是包含文件扩展名的元组序列,用于打开包含模块的文件的模式,以及来自模块中定义的常量的类型代码。 此表是不完整的,因为某些可导入的模块或包类型不对应到单个文件。
$ python3 importlib_suffixes.py
source: ['.py']
debug: ['.pyc']
optimized: ['.pyc']
bytecode: ['.pyc']
extension: ['.cpython-36m-darwin.so', '.abi3.so', '.so']
导入模块
importlib
中的高级 api 使得在给定绝对或相对名称的情况下导入模块变得简单。 使用相对模块名称时,将包含模块的包指定为单独的参数。
importlib_import_module.py
import importlib
m1 = importlib.import_module('example.submodule')
print(m1)
m2 = importlib.import_module('.submodule', package='example')
print(m2)
print(m1 is m2)
import_module()
的返回值是导入创建的模块对象。
$ python3 importlib_import_module.py
importing example package
importing submodule
true
如果模块不能被导入 import_module()
将引发 importerror
错误。
importlib_import_module_error.py
import importlib
try:
importlib.import_module('example.nosuchmodule')
except importerror as err:
print('error:', err)
错误消息包含缺少的模块的名称。
$ python3 importlib_import_module_error.py
importing example package
error: no module named 'example.nosuchmodule'
要重新载入已有模块,使用 reload()
。
importlib_reload.py
import importlib
m1 = importlib.import_module('example.submodule')
print(m1)
m2 = importlib.reload(m1)
print(m1 is m2)
reload()
的返回值是新模块。 根据使用的加载器类型不同,它可能是相同的模块实例。
$ python3 importlib_reload.py
importing example package
importing submodule
importing submodule
true
加载器
importlib
中的低级 api 提供对 loader 对象的访问,如中 sys
模块一节所述。 要获取模块的加载器,请使用 find_loader()
。 然后获取模块,使用 loader 的 load_module()
方法。
importlib_find_loader.py
import importlib
loader = importlib.find_loader('example')
print('loader:', loader)
m = loader.load_module()
print('module:', m)
这个示例加载了 example
包的顶层。
$ python3 importlib_find_loader.py
loader: <_frozen_importlib_external.sourcefileloader object at
0x101fe1828>
importing example package
module:
包中的子模块需要使用包中的路径单独加载。 在下面的示例中,首先加载包,然后将其路径传递给 find_loader()
以创建能够加载子模块的加载器。
importlib_submodule.py
import importlib
pkg_loader = importlib.find_loader('example')
pkg = pkg_loader.load_module()
loader = importlib.find_loader('submodule', pkg.__path__)
print('loader:', loader)
m = loader.load_module()
print('module:', m)
与 import_module()
不同,子模块的名称应该没有任何相对路径前缀,因为加载器已经受到包路径的约束。
$ python3 importlib_submodule.py
importing example package
loader: <_frozen_importlib_external.sourcefileloader object at
0x101fe1f28>
importing submodule
module:
参见
- -- 导入钩子,模块搜索路径以及
sys
模块中的其他相关机器。- -- 以编程方式从模块加载信息。
- -- 新的 import 钩子。
- -- 过去的 import 钩子。
- -- 消除pyo文件。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 cc 协议,如果我们的工作有侵犯到您的权益,请及时联系金年会app官方网。