importlib — 导入的实现 — Python 文档

来自菜鸟教程
Python/docs/3.10/library/importlib
跳转至:导航、​搜索

importlib — import 的实现

3.1 版中的新功能。


源代码: :source:`Lib/importlib/__init__.py`



介绍

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 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.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 版中的新功能。

3.7 版更改:当重新加载的模块缺少 ModuleSpec 时,会引发 ModuleNotFoundError


importlib.abc - 与导入相关的抽象基类

源代码: :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 版起已弃用: 改用 MetaPathFinderPathEntryFinder

class importlib.abc.MetaPathFinder

表示 元路径查找器 的抽象基类。 为了兼容性,这是 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 版中的新功能。

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 仅适用于由 importlib.machinery.PathFinder 提供的基于路径的导入子系统。

3.3 版中的新功能。

在 3.10 版更改:不再是 Finder 的子类。

find_spec(fullname, target=None)

为指定模块查找 spec 的抽象方法。 查找器将仅在分配给它的 路径条目 中搜索该模块。 如果找不到规范,则返回 None。 传入时,target 是一个模块对象,查找器可以使用它来对要返回的规范进行更有根据的猜测。 importlib.util.spec_from_loader() 可能有助于实现具体的 PathEntryFinders

3.4 版中的新功能。

find_loader(fullname)

用于为指定模块查找 加载器 的旧方法。 返回 (loader, portion) 的 2 元组,其中 portion 是构成命名空间包一部分的文件系统位置序列。 加载器可以是 None,同时指定 portion 来表示文件系统位置对命名空间包的贡献。 portion 可以使用空列表来表示加载器不是命名空间包的一部分。 如果 loaderNone 并且 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()

一个可选方法,当调用时,应该使查找器使用的任何内部缓存无效。 importlib.machinery.PathFinder.invalidate_caches() 在使所有缓存的查找器的缓存无效时使用。

class importlib.abc.Loader

loader 的抽象基类。 有关加载程序的确切定义,请参阅 PEP 302

希望支持资源读取的加载器应实现 get_resource_reader(fullname) 方法,如 importlib.abc.ResourceReader 所指定。

3.7 版更改: 引入了可选的 get_resource_reader() 方法。

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())。

加载器应该在模块上设置几个属性。 (请注意,重新加载模块时,其中一些属性可能会更改):

exec_module() 可用时,则提供向后兼容的功能。

3.4 版更改: 调用时引发 ImportError 而不是 NotImplementedErrorexec_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.ResourceReader

被 TraversableResources 取代

抽象基类 提供读取 资源 的能力。

从这个 ABC 的角度来看,resource 是一个二进制工件,它是在一个包中提供的。 通常,这类似于位于包的 __init__.py 文件旁边的数据文件。 此类的目的是帮助抽象出对此类数据文件的访问,以便包及其数据文件是否存储在例如 zip 文件与在文件系统上。

对于此类的任何方法,resource 参数应该是一个 类似路径的对象 ,它在概念上仅表示一个文件名。 这意味着 resource 参数中不应包含任何子目录路径。 这是因为读取器所在的包的位置充当“目录”。 因此,目录和文件名的比喻分别是包和资源。 这也是为什么这个类的实例应该直接关联到一个特定的包(而不是潜在地代表多个包或一个模块)。

希望支持资源读取的加载器应提供一个名为 get_resource_reader(fullname) 的方法,该方法返回一个实现此 ABC 接口的对象。 如果 fullname 指定的模块不是包,则此方法应返回 None。 只有当指定的模块是包时,才应返回与此 ABC 兼容的对象。

3.7 版中的新功能。

class importlib.abc.ResourceLoader

loader 的抽象基类,它实现了可选的 PEP 302 协议,用于从存储后端加载任意资源。

自 3.7 版起已弃用:此 ABC 已弃用,以支持通过 importlib.abc.ResourceReader 加载资源。

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)

一个继承自ResourceLoaderExecutionLoader的抽象基类,提供了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

用于实现源(和可选的字节码)文件加载的抽象基类。 该类继承自 ResourceLoaderExecutionLoader,需要实现:

  • 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__ 结尾。

class importlib.abc.Traversable

具有适合遍历目录和打开文件的 pathlib.Path 方法子集的对象。

3.9 版中的新功能。

read_bytes()

将 self 的内容读取为字节。

read_text(encoding=None)

将 self 的内容作为文本阅读。

class importlib.abc.TraversableResources

能够为 files 接口提供服务的资源读取器的抽象基类。 子类 ResourceReader 并提供 ResourceReader 抽象方法的具体实现。 因此,任何提供 TraversableReader 的加载器也提供 ResourceReader。

希望支持资源读取的加载器需要实现这个接口。

3.9 版中的新功能。


importlib.resources – 资源

源代码: :source:`Lib/importlib/resources.py`



3.7 版中的新功能。


该模块利用 Python 的导入系统提供对 内的 资源 的访问。 如果您可以导入包,则可以访问该包中的资源。 可以以二进制或文本模式打开或读取资源。

资源大致类似于目录中的文件,但重要的是要记住这只是一个比喻。 资源和包 不必 作为文件系统上的物理文件和目录存在。

笔记

该模块提供类似于 pkg_resources Basic Resource Access 的功能,而没有该包的性能开销。 这使得读取包中包含的资源更容易,语义更稳定和一致。

该模块的独立向后移植提供了有关 使用 importlib.resources从 pkg_resources 迁移到 importlib.resources 的更多信息。


希望支持资源读取的加载器应实现 get_resource_reader(fullname) 方法,如 importlib.abc.ResourceReader 所指定。

定义了以下类型。

importlib.resources.Package
Package 类型定义为 Union[str, ModuleType]。 这意味着在函数描述接受 Package 的地方,您可以传入字符串或模块。 模块对象必须具有不是 None 的可解析 __spec__.submodule_search_locations
importlib.resources.Resource
此类型描述传递给此包中各种函数的资源名称。 这被定义为 Union[str, os.PathLike]

可以使用以下功能。

importlib.resources.files(package)

返回一个 importlib.resources.abc.Traversable 对象,表示包(think 目录)及其资源(think 文件)的资源容器。 Traversable 可能包含其他容器(想想子目录)。

package 是符合 Package 要求的名称或模块对象。

3.9 版中的新功能。

importlib.resources.as_file(traversable)

给定一个表示文件的 importlib.resources.abc.Traversable 对象,通常来自 importlib.resources.files(),返回一个上下文管理器以在 with 语句中使用。 上下文管理器提供了一个 pathlib.Path 对象。

退出上下文管理器会清除从例如提取资源时创建的任何临时文件 一个压缩文件。

当 Traversable 方法(read_text 等)不足且需要文件系统上的实际文件时,使用 as_file

3.9 版中的新功能。

importlib.resources.open_binary(package, resource)

打开以二进制读取 内的 资源

package 是符合 Package 要求的名称或模块对象。 resource 是要在 package 中打开的资源的名称; 它可能不包含路径分隔符,也可能没有子资源(即 它不能是目录)。 此函数返回一个 typing.BinaryIO 实例,一个打开以供读取的二进制 I/O 流。

importlib.resources.open_text(package, resource, encoding='utf-8', errors='strict')

打开文本阅读 内的 资源 。 默认情况下,资源以 UTF-8 格式打开读取。

package 是符合 Package 要求的名称或模块对象。 resource 是要在 package 中打开的资源的名称; 它可能不包含路径分隔符,也可能没有子资源(即 它不能是目录)。 encodingerrors 与内置 open() 的含义相同。

此函数返回一个 typing.TextIO 实例,一个打开以供读取的文本 I/O 流。

importlib.resources.read_binary(package, resource)

读取并返回 package 中的 resource 的内容为 bytes

package 是符合 Package 要求的名称或模块对象。 resource 是要在 package 中打开的资源的名称; 它可能不包含路径分隔符,也可能没有子资源(即 它不能是目录)。 此函数将资源的内容返回为 bytes

importlib.resources.read_text(package, resource, encoding='utf-8', errors='strict')

读取并返回 packageresource 的内容作为 str。 默认情况下,内容被读取为严格的 UTF-8。

package 是符合 Package 要求的名称或模块对象。 resource 是要在 package 中打开的资源的名称; 它可能不包含路径分隔符,也可能没有子资源(即 它不能是目录)。 encodingerrors 与内置 open() 的含义相同。 此函数将资源的内容返回为 str

importlib.resources.path(package, resource)

资源 的路径作为实际文件系统路径返回。 此函数返回一个上下文管理器,用于 with 语句中。 上下文管理器提供了一个 pathlib.Path 对象。

退出上下文管理器会清除在需要从例如提取资源时创建的任何临时文件 一个压缩文件。

package 是符合 Package 要求的名称或模块对象。 resource 是要在 package 中打开的资源的名称; 它可能不包含路径分隔符,也可能没有子资源(即 它不能是目录)。

importlib.resources.is_resource(package, name)
如果包中有名为 name 的资源,则返回 True,否则返回 False。 请记住,目录是 不是 资源! package 是符合 Package 要求的名称或模块对象。
importlib.resources.contents(package)

在包内的命名项上返回一个可迭代对象。 迭代返回 str 资源(例如 文件)和非资源(例如 目录)。 可迭代对象不会递归到子目录中。

package 是符合 Package 要求的名称或模块对象。


importlib.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.MetaPathFinderimportlib.abc.InspectLoader ABC。

此类仅定义了类方法以减少实例化的需要。

在 3.5 版中更改:作为 PEP 489 的一部分,内置导入器现在实现 Loader.create_module()Loader.exec_module()

class importlib.machinery.FrozenImporter

用于冻结模块的 导入器 。 此类实现 importlib.abc.MetaPathFinderimportlib.abc.InspectLoader ABC。

此类仅定义了类方法以减少实例化的需要。

3.4 版更改: 获得 create_module()exec_module() 方法。

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()。 否则,sys.path_importer_cache 中设置为 None 的条目将被删除。

3.7 版本变更:删除 sys.path_importer_cacheNone 的条目。

在 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 的加载程序。

自 3.10 版起已弃用: 改用 find_spec()

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)

importlib.abc.SourceLoader.path_stats()的具体实现。

set_data(path, data)

importlib.abc.SourceLoader.set_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_code(fullname)

返回从 path 创建的 name 的代码对象。

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__)

加载模块时应使用的 LoaderFinders 应该总是设置这个。

origin

(__file__)

加载模块的位置的名称,例如 内置模块的“builtin”和从源加载的模块的文件名。 通常应该设置“origin”,但它可能是 None(默认值),表示它是未指定的(例如 对于命名空间包)。

submodule_search_locations

(__path__)

用于查找子模块的字符串列表,如果是包(否则为 None)。

loader_state

加载期间使用的额外模块特定数据的容器(或 None)。

cached

(__cached__)

应存储已编译模块的位置的字符串(或 None)。

parent

(__package__)

(只读)模块应作为子模块加载的包的完全限定名称(或顶级模块的空字符串)。 对于包,它与 __name__ 相同。

has_location

布尔值,指示模块的“来源”属性是否指代可加载位置。


importlib.util – 导入器的实用程序代码

源代码: :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.pyccpython-32 字符串来自当前的魔法标签(参见 get_tag();如果 sys.implementation.cache_tag 未定义,则 NotImplementedError 将被引发)。

optimization 参数用于指定字节码文件的优化级别。 空字符串表示没有优化,因此 /foo/bar/baz.py优化 将导致 /foo/bar/__pycache__/baz.cpython-32.pyc 的字节码路径。 None 导致使用解释器的优化级别。 使用任何其他值的字符串表示,因此 /foo/bar/baz.py2优化 将导致 /foo/bar/__pycache__/baz.cpython-32.opt-2.pyc 的字节码路径。 optimization 的字符串表示只能是字母数字,否则会引发 ValueError

debug_override 参数已弃用,可用于覆盖 __debug__ 的系统值。 True 值相当于将 optimization 设置为空字符串。 False 值与将 optimization 设置为 1 相同。 如果 debug_overrideoptimization 都不是 None,那么会引发 TypeError

3.4 版中的新功能。

3.5 版更改: 添加了 优化 参数,并弃用了 debug_override 参数。

3.6 版更改: 接受 类路径对象

importlib.util.source_from_cache(path)

给定 pathPEP 3147 文件名,返回关联的源代码文件路径。 例如,如果 path/foo/bar/__pycache__/baz.cpython-32.pyc,则返回的路径将是 /foo/bar/baz.pypath 不需要存在,但是如果它不符合 PEP 3147PEP 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 参数。

ImportError 如果 name 是相对模块名称但 package 是假值(例如 None 或空字符串)。 ImportError 也会引发一个相对名称会转义其包含的包(例如 从 spam 包中请求 ..bacon)。

3.3 版中的新功能。

3.9 版更改: 为了提高与导入语句的一致性,对于无效的相对导入尝试,引发 ImportError 而不是 ValueError

importlib.util.find_spec(name, package=None)

查找模块的 spec,可以选择相对于指定的 package 名称。 如果模块在 sys.modules 中,则返回 sys.modules[name].__spec__(除非规范是 None 或未设置,在这种情况下 ValueError ] 提出)。 否则使用 sys.meta_path 进行搜索。 如果未找到规范,则返回 None

如果 name 用于子模块(包含点),则自动导入父模块。

namepackageimport_module() 的工作方式相同。

3.4 版中的新功能。

3.7 版更改: 引发 ModuleNotFoundError 而不是 AttributeError 如果 package 实际上不是包(即 缺少 __path__ 属性)。

importlib.util.module_from_spec(spec)

基于 specspec.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 版更改: 接受 类路径对象

importlib.util.source_hash(source_bytes)

以字节形式返回 source_bytes 的哈希值。 基于散列的 .pyc 文件在其标头中嵌入了相应源文件内容的 source_hash()

3.7 版中的新功能。

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))


例子

以编程方式导入

要以编程方式导入模块,请使用 importlib.import_module()

import importlib

itertools = importlib.import_module('itertools')

检查模块是否可以导入

如果您需要确定模块是否可以在不实际执行导入的情况下导入,那么您应该使用 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 源文件,请使用以下方法(仅限 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)
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

设置进口商

对于导入的深度自定义,您通常希望实现一个 importer。 这意味着同时管理 finderloader 方面。 对于查找器,有两种风格可供选择,具体取决于您的需要:元路径查找器路径条目查找器。 前者是你会放在 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))

近似 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)
    sys.modules[absolute_name] = module
    spec.loader.exec_module(module)
    if path is not None:
        setattr(parent_module, child_name, module)
    return module