31.5. importlib — 导入的实现 — Python 文档
31.5. 导入库 - 实施进口
3.1 版中的新功能。
源代码: :source:`Lib/importlib/__init__.py`
31.5.1. 介绍
importlib 包的目的有两个。 一种是在 Python 源代码中提供 import 语句(因此,通过扩展,__import__() 函数)的实现。 这提供了 import 的实现,它可以移植到任何 Python 解释器。 这也提供了一种比 Python 以外的编程语言更容易理解的实现。
二,实现 import 的组件在这个包中公开,使用户更容易创建自己的自定义对象(通常称为 importer)来参与导入过程。
也可以看看
- 进口声明
- import 语句的语言参考。
- 包装规格
- 包装的原始规格。 自撰写本文档以来,某些语义已发生变化(例如 基于 sys.modules 中的
None
重定向)。 - __import__() 函数
- import 语句是这个函数的语法糖。
- PEP 235
- 在不区分大小写的平台上导入
- PEP 263
- 定义 Python 源代码编码
- PEP 302
- 新的导入挂钩
- PEP 328
- 导入:多行和绝对/相对
- PEP 366
- 主模块显式相对导入
- PEP 420
- 隐式命名空间包
- PEP 451
- 导入系统的 ModuleSpec 类型
- PEP 488
- 消除 PYO 文件
- 第 489 章
- 多相扩展模块初始化
- PEP 3120
- 使用 UTF-8 作为默认源编码
- PEP 3147
- PYC 存储库目录
31.5.2. 职能
- importlib.__import__(name, globals=None, locals=None, fromlist=(), level=0)
内置 __import__() 函数的实现。
笔记
模块的编程导入应该使用 import_module() 而不是这个函数。
- importlib.import_module(name, package=None)
导入一个模块。 name 参数指定以绝对或相对方式导入的模块(例如
pkg.mod
或..mod
)。 如果名称以相对术语指定,则 package 参数必须设置为包的名称,该名称将充当解析包名称的锚点(例如import_module('..mod', 'pkg.subpkg')
将导入pkg.mod
)。import_module() 函数充当 importlib.__import__() 的简化包装器。 这意味着该函数的所有语义都源自 importlib.__import__()。 这两个函数最重要的区别是 import_module() 返回指定的包或模块(例如
pkg.mod
),而 __import__() 返回顶级包或模块(例如pkg
)。如果您正在动态导入自解释器开始执行以来创建的模块(例如,创建一个 Python 源文件),您可能需要调用 invalidate_caches() 以便新模块被导入系统。
3.3 更改:父包自动导入。
- importlib.find_loader(name, path=None)
查找模块的加载程序,可选择在指定的 路径 中。 如果模块在 sys.modules 中,则返回
sys.modules[name].__loader__
(除非加载程序为None
或未设置,在这种情况下 ValueError ] 提出)。 否则使用 sys.meta_path 进行搜索。 如果未找到加载程序,则返回None
。带点的名称没有隐式导入其父项,因为这需要加载它们并且可能不需要。 要正确导入子模块,您需要导入子模块的所有父包并使用正确的参数 path。
3.3 版中的新功能。
3.4版本变更:如果没有设置
__loader__
,则引发ValueError,就像属性设置为None
一样。自 3.4 版起已弃用: 改用 importlib.util.find_spec()。
- importlib.invalidate_caches()
使存储在 sys.meta_path 中的查找器的内部缓存无效。 如果 finder 实现了
invalidate_caches()
,那么它将被调用以执行失效。 如果在您的程序运行时创建/安装了任何模块,则应调用此函数以确保所有查找器都会注意到新模块的存在。3.3 版中的新功能。
- importlib.reload(module)
重新加载之前导入的 模块 。 参数必须是一个模块对象,所以它之前必须成功导入。 如果您使用外部编辑器编辑了模块源文件并希望在不离开 Python 解释器的情况下试用新版本,这将非常有用。 返回值是模块对象(如果重新导入导致将不同的对象放置在 sys.modules 中,则可能会有所不同)。
当执行 reload() 时:
重新编译 Python 模块的代码并重新执行模块级代码,通过重用最初加载模块的 loader 定义一组新的对象,这些对象绑定到模块字典中的名称。 扩展模块的
init
函数不会被第二次调用。与 Python 中的所有其他对象一样,旧对象仅在其引用计数降至零后才会被回收。
模块命名空间中的名称更新为指向任何新的或更改的对象。
对旧对象的其他引用(例如模块外部的名称)不会重新引用到新对象,并且如果需要,必须在它们出现的每个命名空间中更新。
还有一些其他注意事项:
重新加载模块时,会保留其字典(包含模块的全局变量)。 名称的重新定义将覆盖旧定义,因此这通常不是问题。 如果模块的新版本未定义由旧版本定义的名称,则旧定义保留。 如果模块维护全局表或对象缓存,则此功能可用于模块的优势 - 通过 try 语句,它可以测试表的存在并在需要时跳过其初始化:
try: cache except NameError: cache = {}
重新加载内置或动态加载的模块通常不是很有用。 不建议重载 sys、__main__、builtins 等关键模块。 在许多情况下,扩展模块不会被设计为多次初始化,并且在重新加载时可能会以任意方式失败。
如果一个模块使用 from ... import ... 从另一个模块导入对象,则为另一个模块调用 reload() 不会重新定义从它导入的对象——一个解决此问题的方法是重新执行 from 语句,另一种方法是使用 import 和限定名称 (module.name)。
如果模块实例化类的实例,重新加载定义类的模块不会影响实例的方法定义——它们继续使用旧的类定义。 对于派生类也是如此。
3.4 版中的新功能。
31.5.3. 导入库 – 与导入相关的抽象基类
源代码: :source:`Lib/importlib/abc.py`
importlib.abc 模块包含 import 使用的所有核心抽象基类。 还提供了核心抽象基类的一些子类来帮助实现核心 ABC。
ABC 层次结构:
object
+-- Finder (deprecated)
| +-- MetaPathFinder
| +-- PathEntryFinder
+-- Loader
+-- ResourceLoader --------+
+-- InspectLoader |
+-- ExecutionLoader --+
+-- FileLoader
+-- SourceLoader
- class importlib.abc.Finder
表示 finder 的抽象基类。
自 3.3 版起已弃用: 改用 MetaPathFinder 或 PathEntryFinder。
- class importlib.abc.MetaPathFinder
表示 元路径查找器 的抽象基类。 为了兼容性,这是 Finder 的子类。
3.3 版中的新功能。
- find_spec(fullname, path, target=None)
为指定模块查找 spec 的抽象方法。 如果这是顶级导入,path 将是
None
。 否则,这是对子包或模块的搜索,并且 path 将是来自父包的 __path__ 的值。 如果找不到规范,则返回None
。 传入时,target
是一个模块对象,查找器可以使用它来对要返回的规范进行更有根据的猜测。3.4 版中的新功能。
- find_module(fullname, path)
用于为指定模块查找 加载器 的旧方法。 如果这是顶级导入,path 将是
None
。 否则,这是对子包或模块的搜索,并且 path 将是来自父包的 __path__ 的值。 如果找不到加载程序,则返回None
。如果定义了 find_spec(),则提供向后兼容的功能。
3.4 版更改: 调用时返回
None
而不是引发 NotImplementedError。 可以使用 find_spec() 来提供功能。自 3.4 版起已弃用: 改用 find_spec()。
- invalidate_caches()
一个可选方法,当调用时,应该使查找器使用的任何内部缓存无效。 importlib.invalidate_caches() 在使 sys.meta_path 上的所有查找器的缓存无效时使用。
3.4 版更改: 调用时返回
None
而不是NotImplemented
。
- class importlib.abc.PathEntryFinder
表示 路径条目查找器 的抽象基类。 尽管它与 MetaPathFinder 有一些相似之处,但
PathEntryFinder
仅适用于PathFinder
提供的基于路径的导入子系统。 出于兼容性原因,此 ABC 是 Finder 的子类。3.3 版中的新功能。
- find_spec(fullname, target=None)
为指定模块查找 spec 的抽象方法。 查找器将仅在分配给它的 路径条目 中搜索该模块。 如果找不到规范,则返回
None
。 传入时,target
是一个模块对象,查找器可以使用它来对要返回的规范进行更有根据的猜测。3.4 版中的新功能。
- find_loader(fullname)
用于为指定模块查找 加载器 的旧方法。 返回
(loader, portion)
的 2 元组,其中portion
是构成命名空间包一部分的文件系统位置序列。 加载器可以是None
,同时指定portion
来表示文件系统位置对命名空间包的贡献。portion
可以使用空列表来表示加载器不是命名空间包的一部分。 如果loader
是None
并且portion
是空列表,那么没有找到命名空间包的加载器或位置(即 找不到模块的任何内容)。如果定义了 find_spec(),则提供向后兼容的功能。
3.4 版更改: 返回
(None, [])
而不是引发 NotImplementedError。 在可提供功能时使用 find_spec()。自 3.4 版起已弃用: 改用 find_spec()。
- find_module(fullname)
Finder.find_module()
的具体实现,相当于self.find_loader(fullname)[0]
。自 3.4 版起已弃用: 改用 find_spec()。
- invalidate_caches()
一个可选方法,当调用时,应该使查找器使用的任何内部缓存无效。
PathFinder.invalidate_caches()
在使所有缓存的查找器的缓存无效时使用。
- class importlib.abc.Loader
loader 的抽象基类。 有关加载程序的确切定义,请参阅 PEP 302。
- create_module(spec)
在导入模块时返回要使用的模块对象的方法。 此方法可能会返回
None
,指示应该发生默认模块创建语义。3.4 版中的新功能。
3.5 版本更改: 从 Python 3.6 开始,定义 exec_module() 时,此方法将不再可选。
- exec_module(module)
导入或重新加载模块时在其自己的命名空间中执行模块的抽象方法。 当调用
exec_module()
时,模块应该已经初始化。 当此方法存在时,必须定义 create_module()。3.4 版中的新功能。
3.6 版更改: create_module() 也必须定义。
- load_module(fullname)
加载模块的传统方法。 如果模块无法加载,则引发 ImportError,否则返回加载的模块。
如果请求的模块已存在于 sys.modules 中,则应使用并重新加载该模块。 否则,加载器应创建一个新模块并将其插入到 sys.modules 中,然后再开始加载,以防止从导入中递归。 如果loader插入了一个模块并且加载失败,必须由loader从sys.modules中移除; 在加载器开始执行之前已经在 sys.modules 中的模块应该单独保留(参见 importlib.util.module_for_loader())。
加载器应该在模块上设置几个属性。 (请注意,重新加载模块时,其中一些属性可能会更改):
__name__
模块的名称。
__file__
存储模块数据的路径(未为内置模块设置)。
__cached__
模块编译版本所在/应该存储的路径(当属性不合适时不设置)。
__path__
指定包内搜索路径的字符串列表。 此属性未在模块上设置。
__package__
模块/包的父包。 如果模块是顶级的,那么它的值为空字符串。 importlib.util.module_for_loader() 装饰器可以处理 __package__ 的细节。
__loader__
用于加载模块的加载器。 importlib.util.module_for_loader() 装饰器可以处理 __package__ 的细节。
当 exec_module() 可用时,则提供向后兼容的功能。
3.4 版更改: 调用时引发 ImportError 而不是 NotImplementedError。 exec_module() 可用时提供的功能。
自 3.4 版起已弃用: 推荐的用于加载模块的 API 是 exec_module()(和 create_module())。 加载器应该实现它而不是 load_module()。 执行 exec_module() 时,导入机制负责 load_module() 的所有其他职责。
- module_repr(module)
一种遗留方法,在实现时计算并以字符串形式返回给定模块的 repr。 模块类型的默认 repr() 将酌情使用此方法的结果。
3.3 版中的新功能。
3.4 版更改: 成为可选方法而不是抽象方法。
自 3.4 版起已弃用:导入机制现在会自动处理此问题。
- class importlib.abc.InspectLoader
loader 的抽象基类,它为检查模块的加载器实现了可选的 PEP 302 协议。
- get_code(fullname)
返回模块的代码对象,如果模块没有代码对象(例如,内置模块就是这种情况),则返回
None
。 如果加载程序找不到请求的模块,则引发 ImportError。笔记
虽然该方法具有默认实现,但为了性能,建议尽可能覆盖它。
3.4 版本变化: 不再抽象,提供具体实现。
- is_package(fullname)
如果模块是包,则返回真值的抽象方法,否则返回假值。 如果 loader 找不到模块,则会引发 ImportError。
3.4 版更改: 引发 ImportError 而不是 NotImplementedError。
- static source_to_code(data, path='<string>')
从 Python 源创建代码对象。
data 参数可以是 compile() 函数支持的任何内容(即 字符串或字节)。 path 参数应该是源代码来源的“路径”,可以是一个抽象的概念(例如 zip 文件中的位置)。
使用后续代码对象,可以通过运行
exec(code, module.__dict__)
在模块中执行它。3.4 版中的新功能。
在 3.5 版更改: 使方法静态。
- exec_module(module)
Loader.exec_module() 的实现。
3.4 版中的新功能。
- load_module(fullname)
Loader.load_module() 的实现。
自 3.4 版起已弃用: 改为使用 exec_module()。
- class importlib.abc.ExecutionLoader
- 一个继承自 InspectLoader 的抽象基类,在实现时,它有助于将模块作为脚本执行。 ABC 代表可选的 PEP 302 协议。
- class importlib.abc.FileLoader(fullname, path)
一个继承自ResourceLoader和ExecutionLoader的抽象基类,提供了
ResourceLoader.get_data()
和ExecutionLoader.get_filename()
的具体实现。fullname 参数是加载器要处理的模块的完全解析名称。 path 参数是模块文件的路径。
3.3 版中的新功能。
- name
加载器可以处理的模块的名称。
- path
模块文件的路径。
- load_module(fullname)
调用 super 的
load_module()
。自 3.4 版起已弃用: 改用 Loader.exec_module()。
- class importlib.abc.SourceLoader
用于实现源(和可选的字节码)文件加载的抽象基类。 该类继承自 ResourceLoader 和 ExecutionLoader,需要实现:
ResourceLoader.get_data()
ExecutionLoader.get_filename()
应该只返回源文件的路径; 不支持无源加载。
该类定义的抽象方法是添加可选的字节码文件支持。 不实现这些可选方法(或导致它们引发 NotImplementedError)会导致加载器仅使用源代码。 实现这些方法允许加载器处理源 和 字节码文件; 它不允许仅提供字节码的 sourceless 加载。 字节码文件是通过删除 Python 编译器的解析步骤来加速加载的优化,因此没有暴露特定于字节码的 API。
- path_stats(path)
可选的抽象方法,它返回一个 dict 包含有关指定路径的元数据。 支持的字典键是:
'mtime'
(必填):代表源代码修改时间的整数或浮点数;'size'
(可选):源代码的字节大小。
字典中的任何其他键都将被忽略,以允许将来进行扩展。 如果无法处理路径,则会引发 OSError。
3.3 版中的新功能。
3.4 版更改: 引发 OSError 而不是 NotImplementedError。
- path_mtime(path)
返回指定路径的修改时间的可选抽象方法。
自 3.3 版起已弃用: 不推荐使用此方法以支持 path_stats()。 您不必实现它,但它仍可用于兼容性目的。 如果无法处理路径,则引发 OSError。
3.4 版更改: 引发 OSError 而不是 NotImplementedError。
- set_data(path, data)
将指定字节写入文件路径的可选抽象方法。 任何不存在的中间目录都将自动创建。
由于路径是只读的(errno.EACCES/PermissionError)而写入路径失败时,不要传播异常。
3.4 版更改: 调用时不再引发 NotImplementedError。
- get_code(fullname)
InspectLoader.get_code()的具体实现。
- exec_module(module)
Loader.exec_module()的具体实现。
3.4 版中的新功能。
- load_module(fullname)
Loader.load_module()的具体实现。
自 3.4 版起已弃用: 改用 exec_module()。
- get_source(fullname)
InspectLoader.get_source()
的具体实现。
- is_package(fullname)
InspectLoader.is_package()的具体实现。 如果一个模块的文件路径(由
ExecutionLoader.get_filename()
提供)是一个名为__init__
的文件,当文件扩展名被删除 和 模块名称本身时,该模块被确定为包不以__init__
结尾。
31.5.4. 导入lib.machinery – 进口商和路径挂钩
源代码: :source:`Lib/importlib/machinery.py`
该模块包含帮助 import 查找和加载模块的各种对象。
- importlib.machinery.SOURCE_SUFFIXES
表示源模块的已识别文件后缀的字符串列表。
3.3 版中的新功能。
- importlib.machinery.DEBUG_BYTECODE_SUFFIXES
表示非优化字节码模块的文件后缀的字符串列表。
3.3 版中的新功能。
自 3.5 版起已弃用: 改用 BYTECODE_SUFFIXES。
- importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES
表示优化字节码模块的文件后缀的字符串列表。
3.3 版中的新功能。
自 3.5 版起已弃用: 改用 BYTECODE_SUFFIXES。
- importlib.machinery.BYTECODE_SUFFIXES
表示字节码模块(包括前导点)的已识别文件后缀的字符串列表。
3.3 版中的新功能。
3.5 版本变更:该值不再依赖于
__debug__
。
- importlib.machinery.EXTENSION_SUFFIXES
表示扩展模块的已识别文件后缀的字符串列表。
3.3 版中的新功能。
- importlib.machinery.all_suffixes()
返回表示标准导入机制识别的模块的所有文件后缀的字符串组合列表。 这是代码的助手,它只需要知道文件系统路径是否可能引用一个模块,而不需要有关模块类型的任何详细信息(例如,inspect.getmodulename())。
3.3 版中的新功能。
- class importlib.machinery.BuiltinImporter
内置模块的 导入器 。 sys.builtin_module_names 中列出了所有已知的内置模块。 此类实现 importlib.abc.MetaPathFinder 和 importlib.abc.InspectLoader ABC。
此类仅定义了类方法以减少实例化的需要。
在 3.5 版中更改:作为 PEP 489 的一部分,内置导入器现在实现
Loader.create_module()
和Loader.exec_module()
- class importlib.machinery.FrozenImporter
用于冻结模块的 导入器 。 此类实现 importlib.abc.MetaPathFinder 和 importlib.abc.InspectLoader ABC。
此类仅定义了类方法以减少实例化的需要。
- class importlib.machinery.WindowsRegistryFinder
Finder 用于在 Windows 注册表中声明的模块。 此类实现 importlib.abc.MetaPathFinder ABC。
此类仅定义了类方法以减少实例化的需要。
3.3 版中的新功能。
自 3.6 版起已弃用: 改为使用 站点 配置。 默认情况下,未来版本的 Python 可能不会启用此查找器。
- class importlib.machinery.PathFinder
sys.path 和包
__path__
属性的 Finder。 此类实现 importlib.abc.MetaPathFinder ABC。此类仅定义了类方法以减少实例化的需要。
- classmethod find_spec(fullname, path=None, target=None)
尝试在 sys.path 上或(如果已定义)在 path 上为由 fullname 指定的模块查找 spec 的类方法。 对于搜索到的每个路径条目,都会检查 sys.path_importer_cache。 如果找到非假对象,则将其用作 路径条目查找器 以查找正在搜索的模块。 如果在 sys.path_importer_cache 中没有找到条目,则在 sys.path_hooks 中搜索路径条目的查找器,如果找到,则存储在 sys.path_importer_cache[ X186X] 以及有关模块的查询。 如果没有找到查找器,则
None
将同时存储在缓存中并返回。3.4 版中的新功能。
3.5 版更改: 如果当前工作目录(由空字符串表示)不再有效,则返回
None
但在 sys.path_importer_cache 中没有缓存任何值]。
- classmethod find_module(fullname, path=None)
find_spec() 的传统包装器。
自 3.4 版起已弃用: 改用 find_spec()。
- classmethod invalidate_caches()
在存储在 sys.path_importer_cache 中的所有查找器上调用 importlib.abc.PathEntryFinder.invalidate_caches()。
在 3.4 版更改: 使用
的当前工作目录调用 sys.path_hooks 中的对象(即 空字符串)。
- class importlib.machinery.FileFinder(path, \*loader_details)
importlib.abc.PathEntryFinder 的具体实现,它缓存来自文件系统的结果。
path 参数是查找器负责搜索的目录。
loader_details 参数是可变数量的 2 项元组,每个元组包含一个加载器和加载器识别的一系列文件后缀。 加载器应该是可调用的,它接受模块名称和找到的文件路径的两个参数。
finder 将根据需要缓存目录内容,为每个模块搜索进行 stat 调用以验证缓存未过时。 由于缓存失效依赖于文件系统的操作系统状态信息的粒度,因此存在搜索模块、创建新文件,然后搜索新文件所代表的模块的潜在竞争条件。 如果操作发生得足够快以适合 stat 调用的粒度,那么模块搜索将失败。 为了防止这种情况发生,当您动态创建模块时,请确保调用 importlib.invalidate_caches()。
3.3 版中的新功能。
- path
查找器将在其中搜索的路径。
- find_spec(fullname, target=None)
尝试在 path 中找到处理 fullname 的规范。
3.4 版中的新功能。
- find_loader(fullname)
尝试在 path 中找到处理 fullname 的加载程序。
- invalidate_caches()
清除内部缓存。
- classmethod path_hook(\*loader_details)
返回用于 sys.path_hooks 的闭包的类方法。 FileFinder 的实例由闭包使用直接提供给闭包的路径参数和间接提供给闭包的 loader_details 返回。
如果闭包的参数不是现有目录,则会引发 ImportError。
- class importlib.machinery.SourceFileLoader(fullname, path)
importlib.abc.SourceLoader 的具体实现,通过子类化 importlib.abc.FileLoader 并提供其他方法的一些具体实现。
3.3 版中的新功能。
- name
此加载程序将处理的模块的名称。
- path
源文件的路径。
- is_package(fullname)
如果 path 似乎是一个包,则返回 true。
- path_stats(path)
- set_data(path, data)
- load_module(name=None)
importlib.abc.Loader.load_module() 的具体实现,其中指定要加载的模块的名称是可选的。
自 3.6 版起已弃用: 改用 importlib.abc.Loader.exec_module()。
- class importlib.machinery.SourcelessFileLoader(fullname, path)
importlib.abc.FileLoader的具体实现,可以导入字节码文件(即 不存在源代码文件)。
请注意,直接使用字节码文件(因此不是源代码文件)会阻止您的模块被所有 Python 实现或更改字节码格式的新版本 Python 使用。
3.3 版中的新功能。
- name
加载器将处理的模块的名称。
- path
字节码文件的路径。
- is_package(fullname)
根据 path 确定模块是否为包。
- get_source(fullname)
返回
None
,因为使用此加载程序时字节码文件没有源。
- load_module(name=None)
importlib.abc.Loader.load_module() 的具体实现,其中指定要加载的模块的名称是可选的。
自 3.6 版起已弃用: 改用 importlib.abc.Loader.exec_module()。
- class importlib.machinery.ExtensionFileLoader(fullname, path)
importlib.abc.ExecutionLoader 扩展模块的具体实现。
fullname 参数指定加载器要支持的模块的名称。 path 参数是扩展模块文件的路径。
3.3 版中的新功能。
- name
加载器支持的模块的名称。
- path
扩展模块的路径。
- create_module(spec)
根据 PEP 489 从给定规范创建模块对象。
3.5 版中的新功能。
- exec_module(module)
根据 PEP 489 初始化给定的模块对象。
3.5 版中的新功能。
- is_package(fullname)
如果文件路径指向基于 EXTENSION_SUFFIXES 的包的
__init__
模块,则返回True
。
- get_code(fullname)
返回
None
作为扩展模块缺少代码对象。
- get_source(fullname)
返回
None
作为扩展模块没有源代码。
- get_filename(fullname)
返回 路径 。
3.4 版中的新功能。
- class importlib.machinery.ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None)
模块的导入系统相关状态的规范。 这通常作为模块的
__spec__
属性公开。 在下面的描述中,括号中的名称给出了直接在模块对象上可用的相应属性。 例如module.__spec__.origin == module.__file__
。 但是请注意,虽然 值 通常是等效的,但它们可能不同,因为两个对象之间没有同步。 因此可以在运行时更新模块的__path__
,而这不会自动反映在__spec__.submodule_search_locations
中。3.4 版中的新功能。
- name
(
__name__
)模块的完全限定名称的字符串。
- loader
(
__loader__
)用于加载的加载器。 对于命名空间包,这应该设置为
None
。- origin
(
__file__
)加载模块的位置的名称,例如 内置模块的“builtin”和从源加载的模块的文件名。 通常应该设置“origin”,但它可能是
None
(默认值),表示未指定。- submodule_search_locations
(
__path__
)用于查找子模块的字符串列表,如果是包(否则为
None
)。- loader_state
加载期间使用的额外模块特定数据的容器(或
None
)。- cached
(
__cached__
)应存储已编译模块的位置的字符串(或
None
)。- parent
(
__package__
)(只读)模块作为子模块(或
None
)所属的包的完全限定名称。- has_location
布尔值,指示模块的“来源”属性是否指代可加载位置。
31.5.5. 导入库工具 – 进口商的实用程序代码
源代码: :source:`Lib/importlib/util.py`
该模块包含有助于构建 导入器 的各种对象。
- importlib.util.MAGIC_NUMBER
表示字节码版本号的字节。 如果您在加载/编写字节码方面需要帮助,请考虑 importlib.abc.SourceLoader。
3.4 版中的新功能。
- importlib.util.cache_from_source(path, debug_override=None, *, optimization=None)
将 PEP 3147/PEP 488 路径返回到与源 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 将被引发)。optimization 参数用于指定字节码文件的优化级别。 空字符串表示没有优化,因此
/foo/bar/baz.py
与的 优化 将导致
/foo/bar/__pycache__/baz.cpython-32.pyc
的字节码路径。None
导致使用解释器的优化级别。 使用任何其他值的字符串表示形式,因此/foo/bar/baz.py
与2
的 优化 将导致/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc
的字节码路径。 optimization 的字符串表示只能是字母数字,否则会引发 ValueError。debug_override 参数已弃用,可用于覆盖
__debug__
的系统值。True
值相当于将 optimization 设置为空字符串。False
值与将 optimization 设置为1
相同。 如果 debug_override 和 optimization 都不是None
,那么会引发 TypeError。3.4 版中的新功能。
3.5 版更改: 添加了 优化 参数,并弃用了 debug_override 参数。
3.6 版更改: 接受 类路径对象 。
- importlib.util.source_from_cache(path)
给定 path 到 PEP 3147 文件名,返回关联的源代码文件路径。 例如,如果 path 是
/foo/bar/__pycache__/baz.cpython-32.pyc
,则返回的路径将是/foo/bar/baz.py
。 path 不需要存在,但是如果它不符合 PEP 3147 或 PEP 488 格式,一个ValueError
升高。 如果未定义sys.implementation.cache_tag
,则会引发 NotImplementedError。3.4 版中的新功能。
3.6 版更改: 接受 类路径对象 。
- importlib.util.decode_source(source_bytes)
解码表示源代码的给定字节并将其作为带有通用换行符的字符串返回(根据
importlib.abc.InspectLoader.get_source()
的要求)。3.4 版中的新功能。
- importlib.util.resolve_name(name, package)
将相对模块名称解析为绝对名称。
如果 name 没有前导点,则简单地返回 name。 这允许使用
importlib.util.resolve_name('sys', __package__)
之类的用法,而无需检查是否需要 package 参数。ValueError 如果 name 是一个相对模块名称但包是一个假值(例如
None
或空字符串)。 ValueError 也引发了一个相对名称会转义其包含的包(例如 从spam
包中请求..bacon
)。3.3 版中的新功能。
- importlib.util.find_spec(name, package=None)
查找模块的 spec,可以选择相对于指定的 package 名称。 如果模块在 sys.modules 中,则返回
sys.modules[name].__spec__
(除非规范是None
或未设置,在这种情况下 ValueError ] 提出)。 否则使用 sys.meta_path 进行搜索。 如果未找到规范,则返回None
。如果 name 用于子模块(包含点),则自动导入父模块。
name 和 package 与
import_module()
的工作方式相同。3.4 版中的新功能。
- importlib.util.module_from_spec(spec)
基于 spec 和 spec.loader.create_module 创建一个新模块。
如果 spec.loader.create_module 不返回
None
,则不会重置任何预先存在的属性。 此外,如果在访问 spec 或在模块上设置属性时触发,则不会引发 AttributeError。此函数优于使用 types.ModuleType 创建新模块,因为 spec 用于在模块上设置尽可能多的导入控制属性。
3.5 版中的新功能。
- @importlib.util.module_for_loader
importlib.abc.Loader.load_module() 的 装饰器 来处理选择要加载的正确模块对象。 装饰方法应该有一个带有两个位置参数的调用签名(例如
load_module(self, module)
) 的第二个参数将是加载器使用的模块 object。 请注意,由于假设有两个参数,装饰器不适用于静态方法。装饰方法将接收要加载的模块的 name,如预期的 loader。 如果在 sys.modules 中未找到该模块,则会构建一个新模块。 不管模块来自哪里,__loader__ 设置为 self 和 __package__ 是基于什么设置的 importlib.abc.InspectLoader.is_package()[ X173X] 返回(如果可用)。 这些属性被无条件设置以支持重新加载。
如果装饰方法引发异常并且将模块添加到 sys.modules,则该模块将被删除以防止部分初始化的模块留在 sys.modules 中]。 如果模块已经在 sys.modules 中,那么它就被留下。
3.3 版更改:__loader__ 和 __package__ 自动设置(如果可能)。
3.4 版本更改: 无条件设置 __name__、__loader__ __package__ 以支持重新加载。
自 3.4 版起已弃用:导入机制现在直接执行此功能提供的所有功能。
- @importlib.util.set_loader
importlib.abc.Loader.load_module() 的 decorator 设置返回模块的 __loader__ 属性。 如果该属性已设置,则装饰器不执行任何操作。 假设包装方法的第一个位置参数(即
self
) 是 __loader__ 应该设置的。3.4 版更改: 设置
__loader__
如果设置为None
,就好像该属性不存在一样。自 3.4 版起已弃用:导入机制会自动处理此问题。
- @importlib.util.set_package
importlib.abc.Loader.load_module() 的 decorator 设置返回模块的 __package__ 属性。 如果设置了 __package__ 并且具有
None
以外的值,则不会更改。自 3.4 版起已弃用:导入机制会自动处理此问题。
- importlib.util.spec_from_loader(name, loader, *, origin=None, is_package=None)
基于加载器创建
ModuleSpec
实例的工厂函数。 这些参数的含义与它们对 ModuleSpec 的含义相同。 该函数使用可用的 loader API,例如InspectLoader.is_package()
,来填充规范中任何缺失的信息。3.4 版中的新功能。
- importlib.util.spec_from_file_location(name, location, *, loader=None, submodule_search_locations=None)
基于文件路径创建
ModuleSpec
实例的工厂函数。 缺少的信息将通过使用加载器 API 并暗示模块将基于文件来填充到规范中。3.4 版中的新功能。
3.6 版更改: 接受 类路径对象 。
- class importlib.util.LazyLoader(loader)
一个类,它推迟模块加载器的执行,直到模块有一个属性被访问。
此类 only 与定义 exec_module() 的加载器一起使用,因为需要控制模块使用的模块类型。 出于同样的原因,加载器的 create_module() 方法必须返回
None
或其__class__
属性可以在不使用 插槽[ X180X]。 最后,替换放置在 sys.modules 中的对象的模块将无法工作,因为无法安全地正确替换整个解释器中的模块引用; ValueError 如果检测到这样的替换,则会引发。笔记
对于启动时间至关重要的项目,此类允许在从未使用过的情况下最大限度地降低加载模块的成本。 对于启动时间不是必需的项目,由于在加载过程中创建的错误消息被推迟并因此发生在上下文之外,因此 严重 不鼓励使用此类。
3.5 版中的新功能。
3.6 版本更改: 开始调用 create_module(),移除 importlib.machinery.BuiltinImporter 和 importlib.machinery.ExtensionFileLoader[X20X] 的兼容性警告]。
- classmethod factory(loader)
一个静态方法,它返回一个创建惰性加载器的可调用对象。 这意味着在加载器按类而不是按实例传递的情况下使用。
suffixes = importlib.machinery.SOURCE_SUFFIXES loader = importlib.machinery.SourceFileLoader lazy_loader = importlib.util.LazyLoader.factory(loader) finder = importlib.machinery.FileFinder(path, (lazy_loader, suffixes))
31.5.6. 例子
31.5.6.1。 以编程方式导入
要以编程方式导入模块,请使用 importlib.import_module()。
import importlib
itertools = importlib.import_module('itertools')
31.5.6.2. 检查模块是否可以导入
如果您需要确定模块是否可以在不实际执行导入的情况下导入,那么您应该使用 importlib.util.find_spec()。
import importlib.util
import sys
# For illustrative purposes.
name = 'itertools'
spec = importlib.util.find_spec(name)
if spec is None:
print("can't find the itertools module")
else:
# If you chose to perform the actual import ...
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Adding the module to sys.modules is optional.
sys.modules[name] = module
31.5.6.3. 直接导入源文件
要直接导入 Python 源文件,请使用以下方法(仅限 Python 3.5 和更新版本):
import importlib.util
import sys
# For illustrative purposes.
import tokenize
file_path = tokenize.__file__
module_name = tokenize.__name__
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Optional; only necessary if you want to be able to import the module
# by name later.
sys.modules[module_name] = module
31.5.6.4. 设置进口商
对于导入的深度自定义,您通常希望实现一个 importer。 这意味着同时管理 finder 和 loader 方面。 对于查找器,有两种风格可供选择,具体取决于您的需要:元路径查找器或路径条目查找器。 前者是你会放在 sys.meta_path 上的东西,而后者是你在 sys.path_hooks 上使用 path entry hook 创建的东西,它与 一起使用]sys.path 条目可能会创建一个查找器。 此示例将向您展示如何注册您自己的导入器,以便导入使用它们(要为自己创建导入器,请阅读此包中定义的相应类的文档):
import importlib.machinery
import sys
# For illustrative purposes only.
SpamMetaPathFinder = importlib.machinery.PathFinder
SpamPathEntryFinder = importlib.machinery.FileFinder
loader_details = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)
# Setting up a meta path finder.
# Make sure to put the finder in the proper location in the list in terms of
# priority.
sys.meta_path.append(SpamMetaPathFinder)
# Setting up a path entry finder.
# Make sure to put the path hook in the proper location in the list in terms
# of priority.
sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))
31.5.6.5。 逼近 importlib.import_module()
导入本身是用 Python 代码实现的,这使得通过 importlib 暴露大部分导入机制成为可能。 下面通过提供 importlib.import_module() 的近似实现来帮助说明 importlib 公开的各种 API(Python 3.4 和更新版本用于 importlib,Python 3.6 和更新版本用于代码的其他部分)。
import importlib.util
import sys
def import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
sys.modules[absolute_name] = module
if path is not None:
setattr(parent_module, child_name, module)
return module