importlibimport 的实现

3.1 版本新增。

源代码: Lib/importlib/__init__.py


简介

importlib 包的目的是三重的。

一是提供 Python 源代码中 import 语句(以及扩展的 __import__() 函数)的实现。这提供了可移植到任何 Python 解释器的 import 实现。这也提供了一个比用 Python 以外的编程语言实现的更容易理解的实现。

二是,实现 import 的组件在此包中公开,使用户更容易创建自己的自定义对象(统称为 导入器)参与导入过程。

三是,该软件包包含用于管理 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 和其他关键模块。在许多情况下,扩展模块的设计目的不是被初始化多次,并且在重新加载时可能会以任意方式失败。

如果一个模块使用 fromimport … 从另一个模块导入对象,则为其他模块调用 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 中的模块应该保持不变。

加载器应在模块上设置多个属性(请注意,某些属性可以在重新加载模块时更改)

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 支持资源加载。

abstractmethod get_data(path)

一个抽象方法,用于返回位于 *path* 处的数据的字节。具有允许存储任意数据的类文件存储后端的加载器可以实现此抽象方法,以直接访问存储的数据。如果找不到 *path*,则应引发 OSError 。*path* 应该使用模块的 __file__ 属性或包的 __path__ 中的项来构造。

在 3.4 版本中变更: 引发 OSError 而不是 NotImplementedError

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)

一个继承自 ResourceLoaderExecutionLoader 的抽象基类,提供了 ResourceLoader.get_data()ExecutionLoader.get_filename() 的具体实现。

fullname 参数是加载器要处理的模块的完整解析名称。path 参数是模块文件的路径。

在 3.3 版本中添加。

name

加载器可以处理的模块的名称。

path

模块文件的路径。

load_module(fullname)

调用父类的 load_module()

3.4 版本起已弃用: 请改用 Loader.exec_module()

abstractmethod get_filename(fullname)

返回 path

abstractmethod get_data(path)

以二进制文件形式读取 path 并返回其中的字节。

class importlib.abc.SourceLoader

用于实现源代码(和可选的字节码)文件加载的抽象基类。该类同时继承自 ResourceLoaderExecutionLoader,要求实现以下方法:

此类定义的抽象方法用于添加可选的字节码文件支持。不实现这些可选方法(或导致它们引发 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.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

在 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_cacheNone 的条目。

在 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

查找器将在其中搜索的路径。

find_spec(fullname, target=None)

尝试在 path 中查找处理 fullname 的规范。

在 3.4 版本中添加。

invalidate_caches()

清除内部缓存。

classmethod path_hook(*loader_details)

一个类方法,返回一个闭包,用于 sys.path_hooksFileFinder 的实例由闭包返回,该实例直接使用传递给闭包的 path 参数,并间接使用 loader_details 参数。

如果闭包的参数不是一个已存在的目录,则会引发 ImportError 异常。

class importlib.machinery.SourceFileLoader(fullname, path)

通过继承 importlib.abc.FileLoader 并提供其他方法的一些具体实现,来实现 importlib.abc.SourceLoader 的具体实现。

在 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 参数是扩展模块文件的路径。

请注意,默认情况下,如果扩展模块没有实现多阶段初始化(请参阅 PEP 489),即使它在其他情况下可以成功导入,在子解释器中导入扩展模块也会失败。

在 3.3 版本中添加。

在 3.12 版本中变更: 现在在子解释器中使用需要多阶段初始化。

name

加载器支持的模块的名称。

path

扩展模块的路径。

create_module(spec)

根据 PEP 489 从给定的规范创建模块对象。

3.5 版本新增。

exec_module(module)

根据 PEP 489 初始化给定的模块对象。

3.5 版本新增。

is_package(fullname)

如果文件路径指向包的 __init__ 模块,则基于 EXTENSION_SUFFIXES 返回 True

get_code(fullname)

由于扩展模块缺少代码对象,因此返回 None

get_source(fullname)

由于扩展模块没有源代码,因此返回 None

get_filename(fullname)

返回 path

在 3.4 版本中添加。

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。稍后会自动将其设置为命名空间包的特殊对象。

loader_state

finder 可以将此属性设置为一个对象,其中包含加载模块时要使用的其他特定于模块的数据。否则应将其设置为 None

cached

模块代码的编译版本的文件的文件名(请参阅 module.__cached__)。 finder 应始终设置此属性,但对于不需要存储编译代码的模块,该属性可能为 None

parent

(只读)模块所在的包的完全限定名称(对于顶级模块,则为空字符串)。请参阅 module.__package__。如果模块是一个包,则这与 name 相同。

has_location

如果规范的 origin 引用可加载的位置,则为 True,否则为 False。此值会影响如何解释 origin 以及如何填充模块的 __file__

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 – 导入器的实用代码

源代码: Lib/importlib/util.py


此模块包含有助于构建导入器的各种对象。

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.pyccpython-32 字符串来自当前魔术标记 (请参阅 get_tag();如果未定义 sys.implementation.cache_tag,则将引发 NotImplementedError)。

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

debug_override 参数已弃用,可用于覆盖系统的 __debug__ 值。True 值等效于将 optimization 设置为空字符串。False 值与将 optimization 设置为 1 相同。如果 debug_overrideoptimization 都不为 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.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 参数。

如果 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 用于子模块(包含点),则会自动导入父模块。

namepackage 的工作方式与 import_module() 相同。

在 3.4 版本中添加。

在 3.7 版本中更改: 如果 package 实际上不是一个包(即缺少 __path__ 属性),则引发 ModuleNotFoundError 而不是 AttributeError

importlib.util.module_from_spec(spec)

基于 specspec.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.BuiltinImporterimportlib.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