importlib --- import 的实现

在 3.1 版本加入。

源代码: Lib/importlib/__init__.py


引言

importlib 包有三个目的。

其一,在 Python 源代码中提供 import 语句(并由此引申到 __import__() 函数)的实现。这提供了一个可移植到任何 Python 解释器的 import 实现。它还提供了一个比用 Python 以外的编程语言实现的更容易理解的实现。

其二,此包中公开了实现 import 的组件,使用户能更容易地创建他们自己的自定义对象(通常称为 importer (导入器))来参与导入过程。

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

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

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

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 向后兼容而存在。

abstractmethod get_data(path)

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

在 3.4 版更改: 现在会引发 OSError 而不是 NotImplementedError

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)

一个继承自 ResourceLoaderExecutionLoader 的抽象基类,提供了 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_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 版起已弃用,将在 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.MetaPathFinderimportlib.abc.InspectLoader 抽象基类。

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

在 3.5 版本发生变更: 作为 PEP 489 的一部分,内置导入器现在实现了 Loader.create_module()Loader.exec_module()

class importlib.machinery.FrozenImporter

一个用于冻结模块的 importer。此类实现了 importlib.abc.MetaPathFinderimportlib.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

查找器将要搜索的路径。

find_spec(fullname, target=None)

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

在 3.4 版本加入。

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

源文件的路径。

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 版本起弃用,将在 3.15 版本中移除: 请改用 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)

返回从 pathname 创建的代码对象。

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

扩展模块的路径。

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

用于加载模块的 loader(见 module.__loader__)。finder 应该总是设置此属性。

origin

loader 应用于加载模块的位置(见 module.__file__)。例如,对于从 .py 文件加载的模块,这就是文件名。finder 应该总是将此属性设置为对 loader 有意义的值。在没有此值的罕见情况下(如命名空间包),应将其设置为 None

submodule_search_locations

一个(可能为空的)字符串 sequence,枚举了包的子模块将被找到的位置(见 module.__path__)。大多数情况下,此列表中只有一个目录。

finder 应该将此属性设置为一个序列,即使是空序列,以向导入系统指示该模块是一个包。对于非包模块,应将其设置为 None。对于命名空间包,它稍后会自动设置为一个特殊对象。

loader_state

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

cached

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

parent

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

has_location

如果 spec 的 origin 指向一个可加载的位置,则为 True,否则为 False。此值影响 origin 的解释方式以及模块的 __file__ 的填充方式。

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 -- 导入器的工具代码

源代码: Lib/importlib/util.py


此模块包含有助于构建 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.pycNone 会导致使用解释器的优化级别。任何其他值的字符串表示形式都将被使用,因此对于 /foo/bar/baz.py,若 optimization2,将导致字节码路径为 /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 版本发生变更: 接受 path-like object

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 版本发生变更: 接受 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 是一个子模块(包含一个点),父模块将被自动导入。

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 相同。该函数使用可用的 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.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")

直接导入源文件

此方法应谨慎使用:它是对直接指定文件路径的 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