importlib
— import
的实现¶
3.1 版本新增。
源代码: Lib/importlib/__init__.py
简介¶
importlib
包的目的是三重的。
一是提供 Python 源代码中 import
语句(以及扩展的 __import__()
函数)的实现。这提供了可移植到任何 Python 解释器的 import
实现。这也提供了一个比用 Python 以外的编程语言实现的更容易理解的实现。
二是,实现 import
的组件在此包中公开,使用户更容易创建自己的自定义对象(统称为 导入器)参与导入过程。
三是,该软件包包含用于管理 Python 包的其他功能模块
importlib.metadata
提供对第三方发行版元数据的访问。importlib.resources
提供了从 Python 包访问非代码“资源”的例程。
另请参阅
- import 语句
关于
import
语句的语言参考。- 包规范
包的原始规范。 自编写本文档以来,某些语义已更改(例如,根据
sys.modules
中的None
重定向)。__import__()
函数import
语句是此函数的语法糖。- sys.path 模块搜索路径的初始化
sys.path
的初始化。- PEP 235
在不区分大小写的平台上导入
- PEP 263
定义 Python 源代码编码
- PEP 302
新的导入钩子
- PEP 328
导入:多行和绝对/相对
- PEP 366
主模块显式相对导入
- PEP 420
隐式命名空间包
- PEP 451
导入系统的 ModuleSpec 类型
- PEP 488
消除 PYO 文件
- PEP 489
多阶段扩展模块初始化
- PEP 552
确定性的 pycs
- PEP 3120
使用 UTF-8 作为默认源代码编码
- PEP 3147
PYC 存储库目录
函数¶
- 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.invalidate_caches()¶
使存储在
sys.meta_path
中的查找器的内部缓存失效。如果查找器实现了invalidate_caches()
,则将调用它来执行失效操作。如果在程序运行时创建/安装了任何模块,则应调用此函数以确保所有查找器都会注意到新模块的存在。在 3.3 版本中添加。
在 3.10 版本中更改: 在同一命名空间已被导入后,在不同的
sys.path
位置创建/安装的命名空间包也会被注意到。
- importlib.reload(module)¶
重新加载之前导入的 module。参数必须是模块对象,因此它必须之前已成功导入。如果您使用外部编辑器编辑了模块源文件,并希望在不离开 Python 解释器的情况下试用新版本,这将非常有用。返回值是模块对象(如果重新导入导致将不同的对象放入
sys.modules
中,则该对象可能会有所不同)。当
reload()
执行时Python 模块的代码会被重新编译,并且会重新执行模块级别的代码,从而通过重用最初加载模块的 加载器 来定义一组新的对象,这些对象会绑定到模块字典中的名称。扩展模块的
init
函数不会被第二次调用。与 Python 中的所有其他对象一样,旧对象仅在其引用计数降至零后才会被回收。
模块命名空间中的名称会被更新以指向任何新的或更改的对象。
对旧对象的其他引用(例如,模块外部的名称)不会重新绑定以引用新对象,如果需要,必须在它们出现的每个命名空间中更新它们。
还有一些其他注意事项
重新加载模块时,它的字典(包含模块的全局变量)会被保留。名称的重新定义会覆盖旧的定义,所以这通常不是问题。如果模块的新版本没有定义旧版本定义的名称,则旧的定义仍然存在。如果模块维护一个全局表或对象缓存,则可以使用此功能 — 通过一个
try
语句,它可以测试该表的存在,并在需要时跳过其初始化try: cache except NameError: cache = {}
重新加载内置模块或动态加载的模块通常不是很有用。不建议重新加载
sys
、__main__
、builtins
和其他关键模块。在许多情况下,扩展模块的设计目的不是被初始化多次,并且在重新加载时可能会以任意方式失败。如果一个模块使用
from
…import
… 从另一个模块导入对象,则为其他模块调用reload()
不会重新定义从中导入的对象 — 一种解决方法是重新执行from
语句,另一种方法是使用import
和限定名称 (module.name) 来代替。如果一个模块实例化了一个类的实例,则重新加载定义该类的模块不会影响实例的方法定义 — 它们将继续使用旧的类定义。派生类也是如此。
在 3.4 版本中添加。
在 3.7 版本中更改: 当重新加载的模块缺少
ModuleSpec
时,会引发ModuleNotFoundError
。
importlib.abc
– 与导入相关的抽象基类¶
源代码: Lib/importlib/abc.py
importlib.abc
模块包含 import
使用的所有核心抽象基类。还提供了一些核心抽象基类的子类,以帮助实现核心 ABC。
ABC 层次结构
object
+-- MetaPathFinder
+-- PathEntryFinder
+-- Loader
+-- ResourceLoader --------+
+-- InspectLoader |
+-- ExecutionLoader --+
+-- FileLoader
+-- SourceLoader
- class importlib.abc.MetaPathFinder¶
表示 元路径查找器 的抽象基类。
在 3.3 版本中添加。
在 3.10 版本中更改: 不再是
Finder
的子类。- find_spec(fullname, path, target=None)¶
一个用于查找指定模块的 spec 的抽象方法。如果这是一个顶层导入,path 将为
None
。否则,这是一个搜索子包或模块的操作,并且 path 将是父包的__path__
的值。如果找不到 spec,则返回None
。当传入时,target
是一个模块对象,查找器可以使用它来更明智地猜测要返回哪个 spec。importlib.util.spec_from_loader()
对于实现具体的MetaPathFinders
可能很有用。在 3.4 版本中添加。
- invalidate_caches()¶
一个可选的方法,当被调用时,应该使查找器使用的任何内部缓存失效。当使
sys.meta_path
上所有查找器的缓存失效时,由importlib.invalidate_caches()
使用。在 3.4 版本中更改: 调用时返回
None
而不是NotImplemented
。
- class importlib.abc.PathEntryFinder¶
一个表示 路径入口查找器 的抽象基类。虽然它与
MetaPathFinder
有一些相似之处,但PathEntryFinder
仅用于importlib.machinery.PathFinder
提供的基于路径的导入子系统中。在 3.3 版本中添加。
在 3.10 版本中更改: 不再是
Finder
的子类。- find_spec(fullname, target=None)¶
一个用于查找指定模块的 spec 的抽象方法。查找器将仅在分配给它的 路径入口 中搜索模块。如果找不到 spec,则返回
None
。当传入时,target
是一个模块对象,查找器可以使用它来更明智地猜测要返回哪个 spec。importlib.util.spec_from_loader()
对于实现具体的PathEntryFinders
可能很有用。在 3.4 版本中添加。
- invalidate_caches()¶
一个可选的方法,当被调用时,应该使查找器使用的任何内部缓存失效。当使所有缓存的查找器的缓存失效时,由
importlib.machinery.PathFinder.invalidate_caches()
使用。
- class importlib.abc.Loader¶
一个 加载器 的抽象基类。有关加载器的确切定义,请参阅 PEP 302。
希望支持资源读取的加载器应实现
importlib.resources.abc.ResourceReader
指定的get_resource_reader()
方法。在 3.7 版本中更改: 引入了可选的
get_resource_reader()
方法。- create_module(spec)¶
一个返回导入模块时要使用的模块对象的方法。此方法可以返回
None
,表示应进行默认的模块创建语义。在 3.4 版本中添加。
在 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
中,以防止从导入中发生递归。如果加载器插入了一个模块并且加载失败,则加载器必须从sys.modules
中删除它;在加载器开始执行之前已经在sys.modules
中的模块应该保持不变。加载器应在模块上设置多个属性(请注意,某些属性可以在重新加载模块时更改)
module.__cached__
(已弃用)module.__package__
(已弃用)module.__loader__
(已弃用)
当
exec_module()
可用时,将提供向后兼容的功能。在 3.4 版本中更改: 当调用时,引发
ImportError
而不是NotImplementedError
。当exec_module()
可用时,提供功能。3.4 版本已弃用: 加载模块的推荐 API 是
exec_module()
(和create_module()
)。加载器应该实现它而不是load_module()
。当实现了exec_module()
时,导入机制会处理load_module()
的所有其他职责。
- class importlib.abc.ResourceLoader¶
一个用于加载器的抽象基类,它实现了可选的 PEP 302 协议,用于从存储后端加载任意资源。
3.7 版本已弃用: 此 ABC 已被弃用,建议通过
importlib.resources.abc.ResourceReader
支持资源加载。
- class importlib.abc.InspectLoader¶
一个用于加载器的抽象基类,它实现了可选的 PEP 302 协议,用于检查模块的加载器。
- get_code(fullname)¶
返回模块的代码对象,如果模块没有代码对象(例如,对于内置模块),则返回
None
。如果加载器无法找到请求的模块,则引发ImportError
。注意
虽然该方法具有默认实现,但建议在可能的情况下为了提高性能而重写它。
在 3.4 版本中变更: 不再是抽象方法,并提供了具体实现。
- abstractmethod get_source(fullname)¶
一个抽象方法,用于返回模块的源代码。它以文本字符串的形式返回,使用 通用换行符,将所有已识别的行分隔符转换为
'\n'
字符。如果没有可用的源代码(例如,内置模块),则返回None
。如果加载器无法找到指定的模块,则引发ImportError
。在 3.4 版本中变更: 引发
ImportError
而不是NotImplementedError
。
- is_package(fullname)¶
一个可选方法,如果模块是包,则返回 true 值,否则返回 false 值。如果加载器找不到模块,则引发
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 协议。- abstractmethod get_filename(fullname)¶
一个抽象方法,用于返回指定模块的
__file__
的值。如果没有可用的路径,则引发ImportError
。如果有源代码可用,则无论是否使用字节码加载模块,该方法都应返回源代码文件的路径。
在 3.4 版本中变更: 引发
ImportError
而不是NotImplementedError
。
- class importlib.abc.FileLoader(fullname, path)¶
一个继承自
ResourceLoader
和ExecutionLoader
的抽象基类,提供了ResourceLoader.get_data()
和ExecutionLoader.get_filename()
的具体实现。fullname 参数是加载器要处理的模块的完整解析名称。path 参数是模块文件的路径。
在 3.3 版本中添加。
- name¶
加载器可以处理的模块的名称。
- path¶
模块文件的路径。
- load_module(fullname)¶
调用父类的
load_module()
。3.4 版本起已弃用: 请改用
Loader.exec_module()
。
- abstractmethod get_data(path)¶
以二进制文件形式读取 path 并返回其中的字节。
- class importlib.abc.SourceLoader¶
用于实现源代码(和可选的字节码)文件加载的抽象基类。该类同时继承自
ResourceLoader
和ExecutionLoader
,要求实现以下方法:ExecutionLoader.get_filename()
应该只返回源代码文件的路径;不支持无源代码加载。
此类定义的抽象方法用于添加可选的字节码文件支持。不实现这些可选方法(或导致它们引发
NotImplementedError
)会导致加载器只能处理源代码。实现这些方法允许加载器处理源代码和字节码文件;它不允许只提供字节码的无源代码加载。字节码文件是一种优化,通过删除 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__
结尾,则该模块被确定为包。
- class importlib.abc.ResourceReader¶
已被 TraversableResources 取代
一个 抽象基类,用于提供读取资源的能力。
从此 ABC 的角度来看,资源 是一个随包一起提供的二进制工件。通常,这类似于位于包的
__init__.py
文件旁的数据文件。此类旨在帮助抽象出对此类数据文件的访问,以便无论包及其数据文件是存储在 zip 文件中还是文件系统中,都无关紧要。对于此类的方法,resource 参数应为一个 path-like object,它在概念上仅表示一个文件名。这意味着 resource 参数中不应包含任何子目录路径。这是因为读取器所属的包的位置充当“目录”。因此,目录和文件名的隐喻分别是包和资源。这也是为什么此类的实例应该直接关联到特定的包(而不是可能表示多个包或模块)。
希望支持资源读取的加载器应提供一个名为
get_resource_reader(fullname)
的方法,该方法返回一个实现此 ABC 接口的对象。如果 fullname 指定的模块不是包,则此方法应返回None
。仅当指定的模块是包时,才应返回与此 ABC 兼容的对象。3.7 版本新增。
3.12 版本起已弃用, 将在 3.14 版本中移除: 请改用
importlib.resources.abc.TraversableResources
。- abstractmethod open_resource(resource)¶
返回一个已打开的、用于二进制读取 resource 的类文件对象。
如果找不到资源,则会引发
FileNotFoundError
。
- abstractmethod resource_path(resource)¶
返回 resource 的文件系统路径。
如果资源在文件系统上不存在,则引发
FileNotFoundError
。
- abstractmethod is_resource(name)¶
如果命名的 name 被认为是资源,则返回
True
。 如果 name 不存在,则会引发FileNotFoundError
。
- abstractmethod contents()¶
返回一个包含包内容的字符串的可迭代对象。 请注意,迭代器返回的所有名称不一定是实际的资源,例如,返回
is_resource()
将返回 false 的名称是可以接受的。允许返回非资源名称是为了允许在预先知道包及其资源的存储方式的情况下,非资源名称会有用的情况。 例如,允许返回子目录名称,这样当知道包和资源存储在文件系统上时,可以直接使用这些子目录名称。
抽象方法返回一个不包含任何项的可迭代对象。
- class importlib.abc.Traversable¶
具有
pathlib.Path
方法子集的对象,适用于遍历目录和打开文件。对于文件系统上对象的表示,请使用
importlib.resources.as_file()
。3.9 版本新增。
3.12 版本起已弃用, 将在 3.14 版本中移除: 请改用
importlib.resources.abc.Traversable
。- name¶
抽象。此对象的基本名称,不包含任何父引用。
- abstractmethod iterdir()¶
在
self
中生成Traversable
对象。
- abstractmethod is_dir()¶
如果
self
是目录,则返回True
。
- abstractmethod is_file()¶
如果
self
是文件,则返回True
。
- abstractmethod joinpath(child)¶
返回
self
中的 Traversable 子项。
- abstractmethod __truediv__(child)¶
返回
self
中的Traversable
子项。
- abstractmethod open(mode='r', *args, **kwargs)¶
mode 可以是 ‘r’ 或 ‘rb’,分别以文本或二进制模式打开。返回适合读取的句柄(与
pathlib.Path.open
相同)。当以文本模式打开时,接受编码参数,如
io.TextIOWrapper
接受的参数。
- read_bytes()¶
以字节形式读取
self
的内容。
- read_text(encoding=None)¶
以文本形式读取
self
的内容。
- class importlib.abc.TraversableResources¶
用于资源读取器的抽象基类,能够服务于
importlib.resources.files()
接口。 子类importlib.resources.abc.ResourceReader
并提供importlib.resources.abc.ResourceReader
抽象方法的具体实现。因此,任何提供importlib.abc.TraversableResources
的加载器也提供 ResourceReader。希望支持资源读取的加载器应实现此接口。
3.9 版本新增。
3.12 版本起已弃用, 将在 3.14 版本中移除: 请改用
importlib.resources.abc.TraversableResources
。- abstractmethod files()¶
返回已加载包的
importlib.resources.abc.Traversable
对象。
importlib.machinery
– 导入器和路径钩子¶
源代码: 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。此类仅定义类方法,以减轻实例化的需要。
在 3.4 版本中更改: 增加了
create_module()
和exec_module()
方法。
- class importlib.machinery.WindowsRegistryFinder¶
在 Windows 注册表中声明的模块的查找器。此类实现了
importlib.abc.MetaPathFinder
ABC。此类仅定义类方法,以减轻实例化的需要。
在 3.3 版本中添加。
自 3.6 版本起已弃用: 请改用
site
配置。Python 的未来版本可能默认不启用此查找器。
- class importlib.machinery.PathFinder¶
查找器,用于
sys.path
和包__path__
属性。此类实现了importlib.abc.MetaPathFinder
ABC。此类仅定义类方法,以减轻实例化的需要。
- classmethod find_spec(fullname, path=None, target=None)¶
尝试在
sys.path
上或如果已定义,则在 path 上查找由 fullname 指定的模块的规范的类方法。对于搜索的每个路径条目,都会检查sys.path_importer_cache
。如果找到非假对象,则将其用作路径条目查找器,以查找正在搜索的模块。如果在sys.path_importer_cache
中找不到任何条目,则会搜索sys.path_hooks
,以查找路径条目的查找器,如果找到,则将其与正在查询的模块一起存储在sys.path_importer_cache
中。如果始终找不到查找器,则None
会同时存储在缓存中并返回。在 3.4 版本中添加。
在 3.5 版本中更改: 如果当前工作目录(用空字符串表示)不再有效,则会返回
None
,但在sys.path_importer_cache
中不缓存任何值。
- classmethod invalidate_caches()¶
对
sys.path_importer_cache
中存储的所有定义了此方法的查找器调用importlib.abc.PathEntryFinder.invalidate_caches()
。否则,将删除sys.path_importer_cache
中设置为None
的条目。在 3.7 版本中更改: 删除
sys.path_importer_cache
中None
的条目。
在 3.4 版本中更改: 对于
''
(即空字符串),使用当前工作目录调用sys.path_hooks
中的对象。
- class importlib.machinery.FileFinder(path, *loader_details)¶
importlib.abc.PathEntryFinder
的具体实现,它会缓存文件系统的结果。path 参数是查找器负责搜索的目录。
loader_details 参数是可变数量的 2 项元组,每个元组都包含一个加载器和加载器识别的文件后缀序列。 加载器应为可调用对象,接受模块的名称和找到的文件路径两个参数。
查找器会在必要时缓存目录内容,为每个模块搜索调用 stat,以验证缓存未过时。由于缓存陈旧性依赖于操作系统文件系统状态信息的粒度,因此存在搜索模块、创建新文件,然后搜索新文件所代表的模块的潜在竞争条件。如果操作发生得足够快以适应 stat 调用的粒度,则模块搜索将失败。为了防止这种情况发生,当动态创建模块时,请确保调用
importlib.invalidate_caches()
。在 3.3 版本中添加。
- path¶
查找器将在其中搜索的路径。
- invalidate_caches()¶
清除内部缓存。
- classmethod path_hook(*loader_details)¶
一个类方法,返回一个闭包,用于
sys.path_hooks
。FileFinder
的实例由闭包返回,该实例直接使用传递给闭包的 path 参数,并间接使用 loader_details 参数。如果闭包的参数不是一个已存在的目录,则会引发
ImportError
异常。
- class importlib.machinery.SourceFileLoader(fullname, path)¶
通过继承
importlib.abc.FileLoader
并提供其他方法的一些具体实现,来实现importlib.abc.SourceLoader
的具体实现。在 3.3 版本中添加。
- name¶
此加载器将处理的模块的名称。
- path¶
源文件的路径。
- 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¶
字节码文件的路径。
- 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 参数是扩展模块文件的路径。
请注意,默认情况下,如果扩展模块没有实现多阶段初始化(请参阅 PEP 489),即使它在其他情况下可以成功导入,在子解释器中导入扩展模块也会失败。
在 3.3 版本中添加。
在 3.12 版本中变更: 现在在子解释器中使用需要多阶段初始化。
- name¶
加载器支持的模块的名称。
- path¶
扩展模块的路径。
- is_package(fullname)¶
如果文件路径指向包的
__init__
模块,则基于EXTENSION_SUFFIXES
返回True
。
- get_code(fullname)¶
由于扩展模块缺少代码对象,因此返回
None
。
- get_source(fullname)¶
由于扩展模块没有源代码,因此返回
None
。
- class importlib.machinery.NamespaceLoader(name, path, path_finder)¶
命名空间包的
importlib.abc.InspectLoader
的具体实现。这是私有类的别名,仅为了检查命名空间包上的__loader__
属性而公开。>>> from importlib.machinery import NamespaceLoader >>> import my_namespace >>> isinstance(my_namespace.__loader__, NamespaceLoader) True >>> import importlib.abc >>> isinstance(my_namespace.__loader__, importlib.abc.Loader) True
3.11 版本新增。
- class importlib.machinery.ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None)¶
模块的导入系统相关状态的规范。这通常作为模块的
__spec__
属性公开。 许多这些属性也直接在模块上可用:例如,module.__spec__.origin == module.__file__
。但是请注意,虽然*值*通常是等效的,但它们可能会有所不同,因为两个对象之间没有同步。例如,可以在运行时更新模块的__file__
,这不会自动反映在模块的__spec__.origin
中,反之亦然。在 3.4 版本中添加。
- name¶
模块的完全限定名称(请参阅
module.__name__
)。 finder 应该始终将此属性设置为非空字符串。
- loader¶
用于加载模块的 加载器(请参阅
module.__loader__
)。 finder 应该始终设置此属性。
- origin¶
加载器 应加载模块的位置(请参阅
module.__file__
)。例如,对于从.py
文件加载的模块,这是文件名。 finder 应始终将此属性设置为对 加载器 有意义的值。在不常见的情况下(例如对于命名空间包),应将其设置为None
。
- submodule_search_locations¶
一个(可能为空的)字符串 序列,枚举将找到包的子模块的位置(请参阅
module.__path__
)。大多数情况下,此列表中只有一个目录。finder 应将此属性设置为序列,即使是空序列,以向导入系统指示该模块是一个包。对于非包模块,应将其设置为
None
。稍后会自动将其设置为命名空间包的特殊对象。
- cached¶
模块代码的编译版本的文件的文件名(请参阅
module.__cached__
)。 finder 应始终设置此属性,但对于不需要存储编译代码的模块,该属性可能为None
。
- parent¶
(只读)模块所在的包的完全限定名称(对于顶级模块,则为空字符串)。请参阅
module.__package__
。如果模块是一个包,则这与name
相同。
- class importlib.machinery.AppleFrameworkLoader(name, path)¶
importlib.machinery.ExtensionFileLoader
的一个特例,它能够加载框架格式的扩展模块。为了与 iOS 应用商店兼容,iOS 应用中的*所有*二进制模块都必须是动态库,包含在具有适当元数据的框架中,并存储在打包应用的
Frameworks
文件夹中。每个框架只能有一个二进制文件,并且框架文件夹之外不能有可执行二进制文件。为了满足此要求,在 iOS 上运行时,扩展模块二进制文件*不*打包为
sys.path
上的.so
文件,而是打包为独立的框架。为了发现这些框架,此加载器将针对.fwork
文件扩展名进行注册,.fwork
文件充当sys.path
上二进制文件的原始位置的占位符。.fwork
文件包含Frameworks
文件夹中实际二进制文件的路径(相对于应用包)。为了允许将框架打包的二进制文件解析回原始位置,框架应包含一个.origin
文件,其中包含.fwork
文件的位置(相对于应用包)。例如,考虑导入
from foo.bar import _whiz
的情况,其中_whiz
是使用二进制模块sources/foo/bar/_whiz.abi3.so
实现的,其中sources
是注册在sys.path
上的位置(相对于应用程序包)。此模块*必须*作为Frameworks/foo.bar._whiz.framework/foo.bar._whiz
分发(从模块的完整导入路径创建框架名称),在.framework
目录中包含一个Info.plist
文件,用于将二进制文件标识为框架。foo.bar._whiz
模块在原始位置用sources/foo/bar/_whiz.abi3.fwork
标记文件表示,其中包含路径Frameworks/foo.bar._whiz/foo.bar._whiz
。框架还将包含Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin
,其中包含.fwork
文件的路径。当使用此加载器加载模块时,模块的
__file__
将报告为.fwork
文件的位置。这允许代码使用模块的__file__
作为文件系统遍历的锚点。但是,规范的来源将引用.framework
文件夹中*实际*二进制文件的位置。构建应用的 Xcode 项目负责将
PYTHONPATH
中存在的任何.so
文件转换为Frameworks
文件夹中的框架(包括从模块文件中删除扩展名,添加框架元数据,以及签名生成的框架),并创建.fwork
和.origin
文件。这通常会在 Xcode 项目中使用构建步骤来完成;有关如何构造此构建步骤的详细信息,请参阅 iOS 文档。在 3.13 版本中添加。
可用性:iOS。
- name¶
加载器支持的模块的名称。
- path¶
扩展模块的
.fwork
文件的路径。
importlib.util
– 导入器的实用代码¶
此模块包含有助于构建导入器的各种对象。
- importlib.util.MAGIC_NUMBER¶
表示字节码版本号的字节。如果您需要加载/写入字节码方面的帮助,请考虑使用
importlib.abc.SourceLoader
。在 3.4 版本中添加。
- importlib.util.cache_from_source(path, debug_override=None, *, optimization=None)¶
返回与源 path 关联的字节编译文件的 PEP 3147/PEP 488 路径。例如,如果 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 参数用于指定字节码文件的优化级别。空字符串表示不进行优化,因此,optimization 为
''
的/foo/bar/baz.py
将导致字节码路径为/foo/bar/__pycache__/baz.cpython-32.pyc
。None
会导致使用解释器的优化级别。将使用任何其他值的字符串表示形式,因此,optimization 为2
的/foo/bar/baz.py
将导致字节码路径为/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 版本中更改: 添加了 optimization 参数,并弃用了 debug_override 参数。
在 3.6 版本中更改: 接受路径类对象。
- importlib.util.source_from_cache(path)¶
给定 PEP 3147 文件名的 path,返回关联的源代码文件路径。例如,如果 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', __spec__.parent)
之类的用法,而无需检查是否需要 package 参数。如果 name 是相对模块名称,但是 package 为假值(例如
None
或空字符串),则会引发ImportError
。如果相对名称将逃脱其包含的包(例如,从spam
包内请求..bacon
),也会引发ImportError
。在 3.3 版本中添加。
在 3.9 版本中更改: 为了提高与 import 语句的一致性,对于无效的相对导入尝试,引发
ImportError
,而不是ValueError
。
- importlib.util.find_spec(name, package=None)¶
查找模块的规范,可以选择相对于指定的 package 名称。如果模块在
sys.modules
中,则返回sys.modules[name].__spec__
(除非规范为None
或未设置,在这种情况下会引发ValueError
)。否则,将使用sys.meta_path
进行搜索。如果未找到规范,则返回None
。如果 name 用于子模块(包含点),则会自动导入父模块。
name 和 package 的工作方式与
import_module()
相同。在 3.4 版本中添加。
在 3.7 版本中更改: 如果 package 实际上不是一个包(即缺少
__path__
属性),则引发ModuleNotFoundError
而不是AttributeError
。
- 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.spec_from_loader(name, loader, *, origin=None, is_package=None)¶
一个用于基于加载器创建
ModuleSpec
实例的工厂函数。参数的含义与它们在 ModuleSpec 中的含义相同。该函数使用可用的 加载器 API,例如InspectLoader.is_package()
,来填充 spec 上任何缺失的信息。在 3.4 版本中添加。
- importlib.util.spec_from_file_location(name, location, *, loader=None, submodule_search_locations=None)¶
一个用于基于文件路径创建
ModuleSpec
实例的工厂函数。缺失的信息将通过使用加载器 API 并隐含该模块将基于文件来填充到 spec 中。在 3.4 版本中添加。
在 3.6 版本中更改: 接受路径类对象。
- importlib.util.source_hash(source_bytes)¶
以字节形式返回 source_bytes 的哈希值。基于哈希的
.pyc
文件在其头部嵌入了相应源文件内容的source_hash()
。3.7 版本新增。
- importlib.util._incompatible_extension_module_restrictions(*, disable_check)¶
一个上下文管理器,可以临时跳过扩展模块的兼容性检查。默认情况下,检查是启用的,当在子解释器中导入单阶段初始化模块时,检查将失败。当在具有自己 GIL 的解释器中导入不支持每个解释器 GIL 的多阶段初始化模块时,检查也会失败。
请注意,此函数旨在适应一种不常见的情况;这种情况很可能会最终消失。很有可能这不是您要寻找的。
您可以通过实现多阶段初始化的基本接口 (PEP 489) 并谎报对多个解释器(或每个解释器 GIL)的支持来获得与此函数相同的效果。
警告
使用此函数禁用检查可能会导致意外行为,甚至崩溃。它只应在扩展模块开发期间使用。
在 3.12 版本中添加。
- class importlib.util.LazyLoader(loader)¶
一个类,它会延迟模块加载器的执行,直到模块的属性被访问为止。
这个类 只 适用于定义了
exec_module()
的加载器,因为需要控制模块使用的模块类型。出于同样的原因,加载器的create_module()
方法必须返回None
或一个类型,该类型的__class__
属性可以被修改,同时不使用 slots。最后,替换sys.modules
中放置的对象的模块将无法工作,因为没有办法安全地正确替换整个解释器中的模块引用;如果检测到此类替换,则会引发ValueError
。注意
对于启动时间至关重要的项目,此类允许在模块从未使用的情况下潜在地最大限度地减少加载模块的成本。对于启动时间不重要的项目,由于加载期间创建的错误消息被延迟,从而在上下文之外发生,因此 强烈 不鼓励使用此类。
3.5 版本新增。
在 3.6 版本中更改: 开始调用
create_module()
,删除importlib.machinery.BuiltinImporter
和importlib.machinery.ExtensionFileLoader
的兼容性警告。- 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))
示例¶
以编程方式导入¶
要以编程方式导入模块,请使用 importlib.import_module()
。
import importlib
itertools = importlib.import_module('itertools')
检查是否可以导入模块¶
如果您需要找出是否可以导入模块而不实际执行导入,那么您应该使用 importlib.util.find_spec()
。
请注意,如果 name
是一个子模块(包含点),importlib.util.find_spec()
将导入父模块。
import importlib.util
import sys
# For illustrative purposes.
name = 'itertools'
if name in sys.modules:
print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
# If you chose to perform the actual import ...
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
print(f"{name!r} has been imported")
else:
print(f"can't find the {name!r} module")
直接导入源文件¶
应谨慎使用此方法:它是导入语句的近似表示,其中直接指定文件路径,而不是搜索 sys.path
。应首先考虑替代方法,例如在需要正确的模块时修改 sys.path
,或者在运行 Python 文件产生的全局命名空间合适时使用 runpy.run_path()
。
要直接从路径导入 Python 源文件,请使用以下方法
import importlib.util
import sys
def import_from_path(module_name, file_path):
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module
# For illustrative purposes only (use of `json` is arbitrary).
import json
file_path = json.__file__
module_name = json.__name__
# Similar outcome as `import json`.
json = import_from_path(module_name, file_path)
实现惰性导入¶
下面的示例展示了如何实现惰性导入
>>> import importlib.util
>>> import sys
>>> def lazy_import(name):
... spec = importlib.util.find_spec(name)
... loader = importlib.util.LazyLoader(spec.loader)
... spec.loader = loader
... module = importlib.util.module_from_spec(spec)
... sys.modules[name] = module
... loader.exec_module(module)
... return module
...
>>> lazy_typing = lazy_import("typing")
>>> #lazy_typing is a real module object,
>>> #but it is not loaded in memory yet.
>>> lazy_typing.TYPE_CHECKING
False
设置导入器¶
对于导入的深度自定义,您通常希望实现一个 导入器。这意味着管理 查找器 和 加载器 两方面。对于查找器,根据您的需要有两种选择:元路径查找器 或 路径条目查找器。前者是您放在 sys.meta_path
上的,而后者是您使用 路径条目钩子 在 sys.path_hooks
上创建的,它与 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))
近似 importlib.import_module()
¶
导入本身是用 Python 代码实现的,这使得可以通过 importlib 公开大部分导入机制。以下通过提供 importlib.import_module()
的近似实现,来帮助说明 importlib 公开的各种 API。
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)
sys.modules[absolute_name] = module
spec.loader.exec_module(module)
if path is not None:
setattr(parent_module, child_name, module)
return module