importlib
--- import
的实现¶
在 3.1 版本加入。
源代码: Lib/importlib/__init__.py
引言¶
importlib
包有三个目的。
其一,在 Python 源代码中提供 import
语句(并由此引申到 __import__()
函数)的实现。这提供了一个可移植到任何 Python 解释器的 import
实现。它还提供了一个比用 Python 以外的编程语言实现的更容易理解的实现。
其二,此包中公开了实现 import
的组件,使用户能更容易地创建他们自己的自定义对象(通常称为 importer (导入器))来参与导入过程。
其三,该包包含一些模块,这些模块公开了用于管理 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
确定性的 pyc 文件
- 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
)。如果 name 是以相对方式指定的,那么 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 模块的代码会被重新编译,模块级的代码会重新执行,通过重用最初加载该模块的 loader(加载器),定义了一组新的对象并绑定到模块字典中的名称。扩展模块的
init
函数不会被第二次调用。与 Python 中所有其他对象一样,旧对象只有在它们的引用计数降为零后才会被回收。
模块命名空间中的名称会更新以指向任何新的或更改的对象。
对旧对象的其他引用(例如模块外部的名称)不会被重新绑定以引用新对象,如果需要,必须在它们出现的每个命名空间中进行更新。
还有一些其他注意事项:
当一个模块被重新加载时,它的字典(包含模块的全局变量)会被保留。名称的重新定义将覆盖旧的定义,所以这通常不是问题。如果模块的新版本没有定义旧版本中定义的名称,那么旧的定义仍然存在。如果模块维护一个全局表或对象缓存,这个特性可以被模块利用——通过
try
语句,它可以测试表是否存在,如果需要可以跳过其初始化。try: cache except NameError: cache = {}
重新加载内置或动态加载的模块通常不是很有用。不建议重新加载
sys
、__main__
、builtins
和其他关键模块。在许多情况下,扩展模块的设计不是为了被初始化多次,并且在重新加载时可能会以任意方式失败。如果一个模块使用
from
…import
… 从另一个模块导入对象,为另一个模块调用reload()
并不会重新定义从它导入的对象——一种解决方法是重新执行from
语句,另一种是使用import
和限定名称(module.name)。如果一个模块实例化了一个类的实例,重新加载定义该类的模块不会影响实例的方法定义——它们继续使用旧的类定义。对于派生类也是如此。
在 3.4 版本加入。
在 3.7 版更改: 当被重新加载的模块缺少
ModuleSpec
时,会引发ModuleNotFoundError
。警告
此函数非线程安全。从多个线程调用它可能导致未预期的行为。建议使用
threading.Lock
或其他同步原语来实现线程安全的模块重载。
importlib.abc
– 与 import 相关的抽象基类¶
源代码: Lib/importlib/abc.py
importlib.abc
模块包含了 import
所使用的所有核心抽象基类。此外还提供了一些核心抽象基类的子类,以帮助实现核心 ABC。
ABC 继承结构
object
+-- MetaPathFinder
+-- PathEntryFinder
+-- Loader
+-- ResourceLoader --------+
+-- InspectLoader |
+-- ExecutionLoader --+
+-- FileLoader
+-- SourceLoader
- class importlib.abc.MetaPathFinder¶
一个代表 meta path finder (元路径查找器) 的抽象基类。
在 3.3 版本加入。
在 3.10 版更改: 不再是
Finder
的子类。- find_spec(fullname, path, target=None)¶
用于为指定模块查找 spec (规格) 的抽象方法。如果这是一个顶层导入,path 将为
None
。否则,这是一个对子包或模块的搜索,path 将是父包的__path__
的值。如果找不到规格,则返回None
。传入时,target
是一个模块对象,查找器可以用它来做出更明智的关于返回哪个规格的猜测。importlib.util.spec_from_loader()
可能对实现具体的MetaPathFinders
有用。在 3.4 版本加入。
- invalidate_caches()¶
一个可选方法,当被调用时,应使查找器使用的任何内部缓存失效。在使
sys.meta_path
上所有查找器的缓存失效时,由importlib.invalidate_caches()
使用。在 3.4 版更改: 被调用时返回
None
,而不是NotImplemented
。
- class importlib.abc.PathEntryFinder¶
一个代表 path entry finder (路径条目查找器) 的抽象基类。虽然它与
MetaPathFinder
有些相似之处,但PathEntryFinder
仅用于importlib.machinery.PathFinder
提供的基于路径的导入子系统。在 3.3 版本加入。
在 3.10 版更改: 不再是
Finder
的子类。- find_spec(fullname, target=None)¶
用于为指定模块查找 spec (规格) 的抽象方法。查找器将仅在分配给它的 path entry(路径条目)内搜索模块。如果找不到规格,则返回
None
。传入时,target
是一个模块对象,查找器可以用它来做出更明智的关于返回哪个规格的猜测。importlib.util.spec_from_loader()
可能对实现具体的PathEntryFinders
有用。在 3.4 版本加入。
- invalidate_caches()¶
一个可选方法,当被调用时,应使查找器使用的任何内部缓存失效。当使所有缓存的查找器的缓存失效时,由
importlib.machinery.PathFinder.invalidate_caches()
使用。
- class importlib.abc.Loader¶
一个 loader (加载器) 的抽象基类。有关加载器的确切定义,请参阅 PEP 302。
希望支持资源读取的加载器应实现一个
get_resource_reader()
方法,如importlib.resources.abc.ResourceReader
所指定。在 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 版起已弃用,将在 3.15 版中移除: 推荐的模块加载 API 是
exec_module()
(以及create_module()
)。加载器应该实现它而不是load_module()
。当实现了exec_module()
时,导入机制会负责load_module()
的所有其他职责。
- class importlib.abc.ResourceLoader¶
由 TraversableResources 取代
一个 loader(加载器)的抽象基类,它实现了可选的 PEP 302 协议,用于从存储后端加载任意资源。
自 3.7 版起已弃用: 这个 ABC 已被弃用,建议通过
importlib.resources.abc.TraversableResources
支持资源加载。这个类仅为了与该模块中的其他 ABC 向后兼容而存在。
- class importlib.abc.InspectLoader¶
一个 loader(加载器)的抽象基类,它实现了可选的 PEP 302 协议,用于检查模块的加载器。
- get_code(fullname)¶
返回一个模块的代码对象,如果模块没有代码对象(例如,对于内置模块),则返回
None
。如果加载器找不到请求的模块,则引发ImportError
。备注
虽然该方法有默认实现,但建议为了性能尽可能地重写它。
在 3.4 版更改: 不再是抽象的,并提供了具体实现。
- abstractmethod get_source(fullname)¶
一个返回模块源代码的抽象方法。它以使用 universal newlines(通用换行符)的文本字符串形式返回,将所有识别的行分隔符转换为
'\n'
字符。如果没有可用的源代码(例如内置模块),则返回None
。如果加载器找不到指定的模块,则引发ImportError
。在 3.4 版更改: 现在会引发
ImportError
而不是NotImplementedError
。
- 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 版起已弃用,将在 3.15 版中移除: 请改用
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 版起已弃用,将在 3.15 版中移除: 请改用
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 版起已弃用,将在 3.15 版中移除: 请改用
exec_module()
。
- get_source(fullname)¶
InspectLoader.get_source()
的具体实现。
- is_package(fullname)¶
InspectLoader.is_package()
的具体实现。如果一个模块的文件路径(由ExecutionLoader.get_filename()
提供)在移除文件扩展名后是一个名为__init__
的文件,并且 模块名称本身不以__init__
结尾,那么该模块被确定为一个包。
- class importlib.abc.ResourceReader¶
由 TraversableResources 取代
一个提供读取*资源*能力的 abstract base class (抽象基类)。
从这个 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)¶
返回一个已打开的、用于对*资源*进行二进制读取的 file-like object(类文件对象)。
如果找不到资源,将引发
FileNotFoundError
。
- abstractmethod resource_path(resource)¶
返回到*资源*的文件系统路径。
如果资源在文件系统上没有具体存在,则引发
FileNotFoundError
。
- abstractmethod is_resource(name)¶
如果名为 name 的项目被视为资源,则返回
True
。如果 name 不存在,则引发FileNotFoundError
。
- abstractmethod contents()¶
返回一个包含包内容的字符串的 iterable(可迭代对象)。请注意,并不要求迭代器返回的所有名称都是实际的资源,例如,返回
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¶
一个用于内置模块的 importer。所有已知的内置模块都列在
sys.builtin_module_names
中。此类实现了importlib.abc.MetaPathFinder
和importlib.abc.InspectLoader
抽象基类。此类仅定义了类方法,以减少实例化的需要。
在 3.5 版本发生变更: 作为 PEP 489 的一部分,内置导入器现在实现了
Loader.create_module()
和Loader.exec_module()
- class importlib.machinery.FrozenImporter¶
一个用于冻结模块的 importer。此类实现了
importlib.abc.MetaPathFinder
和importlib.abc.InspectLoader
抽象基类。此类仅定义了类方法,以减少实例化的需要。
在 3.4 版本发生变更: 增加了
create_module()
和exec_module()
方法。
- class importlib.machinery.WindowsRegistryFinder¶
用于在 Windows 注册表中声明的模块的 finder。此类实现了
importlib.abc.MetaPathFinder
抽象基类。此类仅定义了类方法,以减少实例化的需要。
在 3.3 版本加入。
自 3.6 版本起弃用: 请改用
site
配置。未来版本的 Python 可能不会默认启用此查找器。
- class importlib.machinery.PathFinder¶
一个用于
sys.path
和包的__path__
属性的 Finder。此类实现了importlib.abc.MetaPathFinder
抽象基类。此类仅定义了类方法,以减少实例化的需要。
- classmethod find_spec(fullname, path=None, target=None)¶
一个类方法,尝试在
sys.path
上,或者如果定义了 path,则在 path 上查找由 fullname 指定的模块的 spec。对于每个被搜索的路径条目,都会检查sys.path_importer_cache
。如果找到了一个非假值的对象,那么它将被用作 path entry finder 来寻找被搜索的模块。如果在sys.path_importer_cache
中没有找到条目,则会在sys.path_hooks
中搜索该路径条目的查找器,如果找到,则将其存储在sys.path_importer_cache
中,并向其查询模块信息。如果始终没有找到查找器,则会在缓存中存储None
并返回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 参数是可变数量的二元组,每个元组包含一个加载器和加载器识别的文件后缀序列。加载器应为可调用对象,接受两个参数:模块名和找到的文件的路径。
查找器会根据需要缓存目录内容,并在每次模块搜索时进行 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.SourceLoader
的一个具体实现,它通过子类化importlib.abc.FileLoader
并提供其他方法的一些具体实现来完成。在 3.3 版本加入。
- name¶
此加载器将处理的模块的名称。
- path¶
源文件的路径。
- path_stats(path)¶
- set_data(path, data)¶
- load_module(name=None)¶
importlib.abc.Loader.load_module()
的具体实现,其中指定要加载的模块名称是可选的。自 3.6 版本起弃用,将在 3.15 版本中移除: 请改用
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 版本起弃用,将在 3.15 版本中移除: 请改用
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¶
用于加载模块的 loader(见
module.__loader__
)。finder 应该总是设置此属性。
- origin¶
loader 应用于加载模块的位置(见
module.__file__
)。例如,对于从.py
文件加载的模块,这就是文件名。finder 应该总是将此属性设置为对 loader 有意义的值。在没有此值的罕见情况下(如命名空间包),应将其设置为None
。
- submodule_search_locations¶
一个(可能为空的)字符串 sequence,枚举了包的子模块将被找到的位置(见
module.__path__
)。大多数情况下,此列表中只有一个目录。finder 应该将此属性设置为一个序列,即使是空序列,以向导入系统指示该模块是一个包。对于非包模块,应将其设置为
None
。对于命名空间包,它稍后会自动设置为一个特殊对象。
- cached¶
模块代码的编译版本的文件名(见
module.__cached__
)。finder 应该总是设置此属性,但对于不需要存储编译代码的模块,它可能为None
。
- parent¶
(只读)模块所在包的完全限定名称(对于顶层模块则为空字符串)。见
module.__package__
。如果模块是一个包,则此值与name
相同。
- class importlib.machinery.AppleFrameworkLoader(name, path)¶
importlib.machinery.ExtensionFileLoader
的一个特化版本,能够加载框架(Framework)格式的扩展模块。为了与 iOS App Store 兼容,iOS 应用中的所有二进制模块必须是动态库,包含在带有适当元数据的框架中,并存储在打包应用的
Frameworks
文件夹中。每个框架只能有一个二进制文件,并且在 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__
作为文件系统遍历的锚点。但是,spec origin 将引用实际二进制文件在.framework
文件夹中的位置。构建应用的 Xcode 项目负责将
PYTHONPATH
中任何地方的.so
文件转换为Frameworks
文件夹中的框架(包括从模块文件中剥离扩展名、添加框架元数据和对生成的框架进行签名),并创建.fwork
和.origin
文件。这通常通过 Xcode 项目中的构建步骤完成;有关如何构建此步骤的详细信息,请参阅 iOS 文档。在 3.13 版本加入。
可用性:iOS。
- name¶
加载器支持的模块名称。
- path¶
扩展模块的
.fwork
文件的路径。
importlib.util
-- 导入器的工具代码¶
此模块包含有助于构建 importer 的各种对象。
- 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 参数用于指定字节码文件的优化级别。空字符串表示无优化,因此对于
/foo/bar/baz.py
,若 optimization 为''
,将产生字节码路径/foo/bar/__pycache__/baz.cpython-32.pyc
。None
会导致使用解释器的优化级别。任何其他值的字符串表示形式都将被使用,因此对于/foo/bar/baz.py
,若 optimization 为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 版本发生变更: 增加了 optimization 参数,并弃用了 debug_override 参数。
在 3.6 版本发生变更: 接受 path-like object。
- 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 版本发生变更: 接受 path-like object。
- 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)¶
查找模块的 spec,可选地相对于指定的 package 名称。如果模块在
sys.modules
中,则返回sys.modules[name].__spec__
(除非 spec 为None
或未设置,在这种情况下会引发ValueError
)。否则,将使用sys.meta_path
进行搜索。如果未找到 spec,则返回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 相同。该函数使用可用的 loader 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 版本发生变更: 接受 path-like object。
- importlib.util.source_hash(source_bytes)¶
返回 source_bytes 的哈希值(以字节串形式)。基于哈希的
.pyc
文件在其头部嵌入了相应源文件内容的source_hash()
。在 3.7 版本加入。
- importlib.util._incompatible_extension_module_restrictions(*, disable_check)¶
一个可以临时跳过扩展模块兼容性检查的上下文管理器。默认情况下,该检查是启用的,当在子解释器中导入单阶段初始化模块时会失败。当在拥有自己的 GIL 的解释器中导入一个不支持 per-interpreter GIL 的多阶段初始化模块时,它也会失败。
请注意,此函数旨在应对一种不常见的情况;这种情况很可能最终会消失。这很可能不是您要找的东西。
您可以通过实现多阶段初始化的基本接口(PEP 489)并谎报对多解释器(或 per-interpreter 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")
直接导入源文件¶
此方法应谨慎使用:它是对直接指定文件路径的 import 语句的近似模拟,而不是搜索 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 将使用它们(关于为你自己创建导入器,请阅读本包中定义的相应类的文档)。
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()
¶
import 本身是用 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