importlibimport 的实现

在 3.1 版本中添加。

源代码: Lib/importlib/__init__.py


简介

importlib 包的目的是三方面的。

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

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

三是该包包含模块,这些模块公开了用于管理 Python 包方面的其他功能

另请参见

import 语句

import 语句的语言参考。

包规范

包的原始规范。自编写本文档以来,某些语义已发生变化(例如,基于 Nonesys.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 和其他关键模块是不推荐的。在许多情况下,扩展模块并非设计为初始化多次,并且在重新加载时可能会以任意方式失败。

如果模块使用 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)

一个用于查找指定模块的 规范 的抽象方法。如果这是一个顶级导入,则 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__

    模块代码的编译版本的文件名。并非所有模块都设置了此属性(例如,内置模块)。

  • __path__

    包的子模块将被找到的位置列表。大多数情况下,这是一个单一目录。导入系统将此属性传递给 __import__() 和查找器,与 sys.path 相同,但仅针对包。它没有在非包模块上设置,因此可以用作模块是包的指示器。

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

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)

一个可选方法,如果模块是包,则返回真值,否则返回假值。如果加载器找不到模块,则引发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 文件中还是在文件系统中,访问方式都相同。

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

希望支持资源读取的加载器预计会提供一个名为 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.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)

类方法,尝试在 规范 中找到由 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

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

find_spec(fullname, target=None)

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

在版本 3.4 中添加。

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

源文件的路径。

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__ 模块,则返回 True,基于 EXTENSION_SUFFIXES

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

(__name__)

模块的完全限定名称。 查找器 应始终将此属性设置为非空字符串。

loader

(__loader__)

用于加载模块的 加载器查找器 应始终设置此属性。

origin

(__file__)

加载器 应使用的位置来加载模块。例如,对于从 .py 文件加载的模块,这是文件名。 查找器 应始终将此属性设置为对 加载器 有意义的值。在没有一个位置的罕见情况下(例如命名空间包),它应该设置为 None

submodule_search_locations

(__path__)

包的子模块将被找到的位置列表。大多数情况下,这是一个单一目录。 查找器 应将此属性设置为列表,即使是空列表,也要指示导入系统该模块是一个包。对于非包模块,它应该设置为 None。对于命名空间包,它稍后会自动设置为一个特殊对象。

loader_state

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

cached

(__cached__)

模块代码的编译版本的文件名。 查找器 应始终设置此属性,但对于不需要存储编译代码的模块,它可以是 None

parent

(__package__)

(只读) 模块所在的包的完全限定名称(或顶级模块的空字符串)。如果模块是一个包,那么这与 name 相同。

has_location
如果规范的 origin 指向可加载位置,则为 True

否则为 False。此值影响 origin 的解释方式以及模块的 __file__ 的填充方式。

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,则返回值将是 /foo/bar/__pycache__/baz.cpython-32.pyc(对于 Python 3.2)。 cpython-32 字符串来自当前的魔术标签(参见 get_tag();如果 sys.implementation.cache_tag 未定义,则会引发 NotImplementedError)。

optimization 参数用于指定字节码文件的优化级别。空字符串表示没有优化,因此 /foo/bar/baz.pyoptimization'' 将导致字节码路径为 /foo/bar/__pycache__/baz.cpython-32.pycNone 会导致使用解释器的优化级别。任何其他值的字符串表示形式都会被使用,因此 /foo/bar/baz.pyoptimization2 将导致字节码路径为 /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 文件名的路径,返回关联的源代码文件路径。例如,如果路径/foo/bar/__pycache__/baz.cpython-32.pyc,则返回的路径将是 /foo/bar/baz.py路径不必存在,但是如果它不符合 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 中更改: 为了提高与导入语句的一致性,对于无效的相对导入尝试,引发 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 版更改: 接受 路径类对象

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

直接导入源文件

要直接导入 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