importlib
— import
的实现¶
在 3.1 版本中添加。
源代码: Lib/importlib/__init__.py
简介¶
importlib
包的目的是三方面的。
一是提供 import
语句(以及由此扩展的 __import__()
函数)在 Python 源代码中的实现。这提供了 import
的实现,该实现可移植到任何 Python 解释器。这也提供了比用 Python 以外的编程语言实现的实现更容易理解的实现。
二是实现 import
的组件在这个包中公开,使用户更容易创建自己的自定义对象(通常称为 导入器)来参与导入过程。
三是该包包含模块,这些模块公开了用于管理 Python 包方面的其他功能
importlib.metadata
提供对来自第三方发行版的元数据的访问。importlib.resources
提供用于访问 Python 包中的非代码“资源”的例程。
另请参见
- import 语句
import
语句的语言参考。- 包规范
包的原始规范。自编写本文档以来,某些语义已发生变化(例如,基于
None
在sys.modules
中的重定向)。__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)¶
一个用于查找指定模块的 规范 的抽象方法。如果这是一个顶级导入,则 path 将为
None
。否则,这是一个对子包或模块的搜索,并且 path 将是父包的__path__
的值。如果找不到规范,则返回None
。当传入时,target
是一个模块对象,查找器可以使用它来更准确地猜测要返回的规范。importlib.util.spec_from_loader()
可能有助于实现具体的MetaPathFinders
。在版本 3.4 中添加。
- invalidate_caches()¶
一个可选方法,当被调用时,应该使查找器使用的任何内部缓存失效。由
importlib.invalidate_caches()
在使sys.meta_path
上所有查找器的缓存失效时使用。在版本 3.4 中更改: 当被调用时返回
None
而不是NotImplemented
。
- class importlib.abc.PathEntryFinder¶
一个表示 路径条目查找器 的抽象基类。虽然它与
MetaPathFinder
有些相似,但PathEntryFinder
仅用于importlib.machinery.PathFinder
提供的基于路径的导入子系统中。在 3.3 版本中添加。
在版本 3.10 中更改: 不再是
Finder
的子类。- find_spec(fullname, target=None)¶
一个用于查找指定模块的 规范 的抽象方法。查找器将仅在其分配的 路径条目 中搜索模块。如果找不到规范,则返回
None
。当传入时,target
是一个模块对象,查找器可以使用它来更准确地猜测要返回的规范。importlib.util.spec_from_loader()
可能有助于实现具体的PathEntryFinders
。在版本 3.4 中添加。
- invalidate_caches()¶
一个可选方法,当被调用时,应该使查找器使用的任何内部缓存失效。由
importlib.machinery.PathFinder.invalidate_caches()
在使所有缓存的查找器的缓存失效时使用。
- class importlib.abc.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
中的模块应保持不变。加载器应在模块上设置几个属性(注意,当模块被重新加载时,其中一些属性可能会改变)
__name__
模块的完全限定名称。对于已执行的模块,它是
'__main__'
。
__file__
加载器用来加载模块的位置。例如,对于从 .py 文件加载的模块,这是文件名。并非所有模块都设置了此属性(例如,内置模块)。
__cached__
模块代码的编译版本的文件名。并非所有模块都设置了此属性(例如,内置模块)。
__package__
模块所在的包的完全限定名称(或顶级模块的空字符串)。如果模块是一个包,那么它与
__name__
相同。
__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)¶
一个可选方法,如果模块是包,则返回真值,否则返回假值。如果加载器找不到模块,则引发
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 文件中还是在文件系统中,访问方式都相同。对于此类的任何方法,*资源* 参数都应为 路径类对象,它在概念上仅表示一个文件名。这意味着 *资源* 参数中不应包含任何子目录路径。这是因为读取器所针对的包的位置充当“目录”。因此,目录和文件名的隐喻分别是包和资源。这也是为什么此类的实例预计会直接与特定包相关联(而不是可能代表多个包或模块)的原因。
希望支持资源读取的加载器预计会提供一个名为
get_resource_reader(fullname)
的方法,该方法返回一个实现此 ABC 接口的对象。如果 fullname 指定的模块不是包,则此方法应返回None
。仅当指定模块为包时,才应返回与该 ABC 兼容的对象。在版本 3.7 中添加。
版本 3.12 中已弃用,将在版本 3.14 中移除: 建议使用
importlib.resources.abc.TraversableResources
。- abstractmethod open_resource(resource)¶
返回一个已打开的 文件类对象,用于以二进制方式读取 *资源*。
如果找不到资源,则会引发
FileNotFoundError
。
- abstractmethod resource_path(resource)¶
返回资源的文件系统路径。
如果资源在文件系统上不存在,则引发
FileNotFoundError
。
- abstractmethod is_resource(name)¶
如果命名name被认为是资源,则返回
True
。如果name不存在,则引发FileNotFoundError
。
- abstractmethod contents()¶
返回一个关于包内容的字符串的 可迭代对象。请注意,不需要迭代器返回的所有名称都是实际的资源,例如,返回
is_resource()
为假的名称是可以接受的。允许返回非资源名称是为了允许在先验知道包及其资源存储方式的情况下,非资源名称将是有用的。例如,允许返回子目录名称,以便当已知包和资源存储在文件系统上时,这些子目录名称可以直接使用。
抽象方法返回一个没有项目的可迭代对象。
- 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)¶
类方法,尝试在 规范 中找到由 fullname 指定的模块的 规范,该规范由 fullname 指定,位于
sys.path
上,或者如果已定义,则位于 path 上。对于搜索的每个路径条目,都会检查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
上使用。闭包使用直接传递给闭包的路径参数和间接传递的 loader_details 返回FileFinder
的实例。如果闭包的参数不是现有目录,则会引发
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__
模块,则返回True
,基于EXTENSION_SUFFIXES
。
- 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¶
(
__name__
)模块的完全限定名称。 查找器 应始终将此属性设置为非空字符串。
- loader¶
- origin¶
(
__file__
)加载器 应使用的位置来加载模块。例如,对于从 .py 文件加载的模块,这是文件名。 查找器 应始终将此属性设置为对 加载器 有意义的值。在没有一个位置的罕见情况下(例如命名空间包),它应该设置为
None
。- submodule_search_locations¶
(
__path__
)包的子模块将被找到的位置列表。大多数情况下,这是一个单一目录。 查找器 应将此属性设置为列表,即使是空列表,也要指示导入系统该模块是一个包。对于非包模块,它应该设置为
None
。对于命名空间包,它稍后会自动设置为一个特殊对象。- loader_state¶
查找器 可以将此属性设置为一个对象,该对象包含加载模块时使用的其他特定于模块的数据。否则,它应该设置为
None
。- cached¶
模块代码的编译版本的文件名。 查找器 应始终设置此属性,但对于不需要存储编译代码的模块,它可以是
None
。- parent¶
(只读) 模块所在的包的完全限定名称(或顶级模块的空字符串)。如果模块是一个包,那么这与
name
相同。- has_location¶
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
,则返回值将是/foo/bar/__pycache__/baz.cpython-32.pyc
(对于 Python 3.2)。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 版更改: 接受 路径类对象。
- importlib.util.source_from_cache(path)¶
给定一个指向 PEP 3147 文件名的路径,返回关联的源代码文件路径。例如,如果路径是
/foo/bar/__pycache__/baz.cpython-32.pyc
,则返回的路径将是/foo/bar/baz.py
。路径不必存在,但是如果它不符合 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 中更改: 为了提高与导入语句的一致性,对于无效的相对导入尝试,引发
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 版更改: 接受 路径类对象。
- 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")
直接导入源文件¶
要直接导入 Python 源文件,请使用以下方法
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)
sys.modules[module_name] = module
spec.loader.exec_module(module)
实现延迟导入¶
以下示例展示了如何实现延迟导入
>>> 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