Skip to main content

31.5. importlibimport 的实现

3.1 新版功能.

源代码: Lib/importlib/__init__.py


31.5.1. 介绍

importlib 包的目的是双重的。一个是在Python源代码中提供 import 语句的实现(因此,通过扩展,__import__() 函数)。这提供了可移植到任何Python解释器的 import 的实现。这也提供了比在除了Python之外的编程语言中实现的实现更容易理解的实现。

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

参见

import 声明

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文件

PEP 489

多阶段扩展模块初始化

PEP 3120

使用UTF-8作为默认源代码编码

PEP 3147

PYC存储库目录

31.5.2. 功能

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)

找到模块的加载器,可选地在指定的 path 中。如果模块在 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)

重新加载先前导入的 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 新版功能.

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

源代码: 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

abstractmethod find_module(fullname, path=None)

用于为指定模块查找 loader 的抽象方法。最初在 PEP 302 中指定,此方法意味着在 sys.meta_path 和基于路径的导入子系统中使用。

在 3.4 版更改: 返回 None,而不是提高 NotImplementedError

class importlib.abc.MetaPathFinder

表示 meta path finder 的抽象基类。为了兼容性,这是 Finder 的子类。

3.3 新版功能.

find_spec(fullname, path, target=None)

用于为指定模块查找 规格 的抽象方法。如果这是顶级导入,path 将是 None。否则,这是搜索子包或模块,path 将是父包的 __path__ 值。如果找不到spec,则返回 None。当传入时,target 是一个模块对象,finder可以使用它来做一个更有根据的猜测,返回什么规范。

3.4 新版功能.

find_module(fullname, path)

用于为指定模块查找 loader 的传统方法。如果这是顶级导入,path 将是 None。否则,这是搜索子包或模块,path 将是父包的 __path__ 值。如果找不到加载器,则返回 None

如果定义了 find_spec(),则提供向后兼容的功能。

在 3.4 版更改: 返回 None,而不是提高 NotImplementedError。可以使用 find_spec() 提供功能。

3.4 版后已移除: 请改用 find_spec()

invalidate_caches()

一个可选的方法,当被调用时,应该使finder使用的任何内部缓存失效。由 importlib.invalidate_caches() 使用时,使 sys.meta_path 上所有查找器的高速缓存无效。

在 3.4 版更改: 返回 None,而不是 NotImplemented

class importlib.abc.PathEntryFinder

表示 path entry finder 的抽象基类。虽然它与 MetaPathFinder 有一些相似之处,但是 PathEntryFinder 仅用于由 PathFinder 提供的基于路径的导入子系统内。由于兼容性原因,此ABC是 Finder 的子类。

3.3 新版功能.

find_spec(fullname, target=None)

用于为指定模块查找 规格 的抽象方法。查找器将仅在分配给它的 path entry 中搜索模块。如果找不到spec,则返回 None。当传入时,target 是一个模块对象,finder可以使用它来做一个更有根据的猜测,返回什么规范。

3.4 新版功能.

find_loader(fullname)

用于为指定模块查找 loader 的传统方法。返回 (loader, portion) 的2元组,其中 portion 是贡献于命名空间包的一部分的文件系统位置序列。加载器可以是 None,同时指定 portion 来表示文件系统位置对命名空间包的贡献。空列表可用于 portion,以表示加载程序不是命名空间包的一部分。如果 loaderNoneportion 是空列表,则找不到命名空间包的加载器或位置(即,找不到模块的任何东西)。

如果定义了 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()

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

class importlib.abc.Loader

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

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,以防止从导入递归。如果加载器插入一个模块,并且加载失败,则必须由加载器从 sys.modules 中移除;在加载器开始执行之前已经在 sys.modules 中的模块应该被留下(参见 importlib.util.module_for_loader())。

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

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

在 3.4 版更改: 呼叫时提高 ImportError,而不是 NotImplementedError。当 exec_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.ResourceLoader

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

abstractmethod get_data(path)

一种抽象方法,用于返回位于 path 的数据的字节。具有允许存储任意数据的类文件存储后端的装载程序可以实现此抽象方法,以直接访问存储的数据。如果找不到 path,则应提出 OSError。预期 path 将使用模块的 __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)

一个抽象方法,如果模块是一个包,返回一个真值,否则为false值。如果 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 协议。

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)

调用super的 load_module()

3.4 版后已移除: 请改用 Loader.exec_module()

abstractmethod get_filename(fullname)

返回 path

abstractmethod get_data(path)

path 读取为二进制文件,并从中返回字节。

class importlib.abc.SourceLoader

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

这个类定义的抽象方法是添加可选的字节码文件支持。不实现这些可选方法(或使它们引发 NotImplementedError)导致加载器只使用源代码。实现方法允许加载器使用源 and 字节码文件工作;它不允许在仅提供字节码的情况下进行 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__ 结束。

31.5.4. 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 ABCs。

只有这个类定义了类方法,才能减少实例化的需要。

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

class importlib.machinery.FrozenImporter

冷冻模块的 importer。这个类实现了 importlib.abc.MetaPathFinderimportlib.abc.InspectLoader ABCs。

只有这个类定义了类方法,才能减少实例化的需要。

class importlib.machinery.WindowsRegistryFinder

Finder 在Windows注册表中声明的模块。这个类实现了 importlib.abc.Finder ABC。

只有这个类定义了类方法,才能减少实例化的需要。

3.3 新版功能.

3.6 版后已移除: 请改用 site 配置。未来版本的Python可能不会启用此查找器默认情况下。

class importlib.machinery.PathFinder

Findersys.path 和包 __path__ 属性。这个类实现 importlib.abc.MetaPathFinder ABC。

只有这个类定义了类方法,才能减少实例化的需要。

classmethod find_spec(fullname, path=None, target=None)

类方法,尝试为 sys.path 上的 fullname 指定的模块或如果已定义的 path 找到 规格。对于每个搜索的路径条目,将检查 sys.path_importer_cache。如果发现非假对象,则它被用作 path entry finder 来寻找正在被搜索的模块。如果在 sys.path_importer_cache 中没有找到条目,则搜索 sys.path_hooks 以寻找路径条目的查找器,并且如果找到,则在查询关于模块的同时存储在 sys.path_importer_cache 中。如果找不到finder,则 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()

在 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

invalidate_caches()

清除内部缓存。

classmethod path_hook(*loader_details)

返回在 sys.path_hooks 上使用的闭包的类方法。 FileFinder 的实例由闭包使用直接给予闭包的路径参数和间接地使用 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 参数是扩展模块文件的路径。

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)

返回 path

3.4 新版功能.

class importlib.machinery.ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None)

模块的导入系统相关状态的规范。

3.4 新版功能.

name

__name__

模块的完全限定名称的字符串。

loader

__loader__

加载器用于加载。对于命名空间包,应将其设置为 None

origin

__file__

模块加载地点的名称,例如“builtin”用于内置模块,文件名用于从源加载的模块。通常应该设置“origin”,但它可能是 None (默认),它表示未指定。

submodule_search_locations

__path__

用于在哪里找到子模块的字符串列表(如果是包,则为 None)。

loader_state

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

cached

__cached__

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

parent

__package__

(只读)模块作为子模块(或 None)所属的包的完全限定名称。

has_location

布尔值,指示模块的“origin”属性是否指可装入的位置。

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

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 参数用于指定字节码文件的优化级别。空字符串表示无优化,因此具有 ''optimization/foo/bar/baz.py 将导致 /foo/bar/__pycache__/baz.cpython-32.pyc 的字节码路径。 None 使得插值器的优化级别被使用。任何其他值的字符串表示正被使用,因此具有 2optimization/foo/bar/baz.py 将导致 /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 版更改: 添加了 optimization 参数,不推荐使用 debug_override 参数。

在 3.6 版更改: 接受 path-like object

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 版更改: 接受 path-like object

importlib.util.decode_source(source_bytes)

解码表示源代码的给定字节,并将其作为具有通用换行符的字符串(根据 importlib.abc.InspectLoader.get_source() 的要求)返回。

3.4 新版功能.

importlib.util.resolve_name(name, package)

将相对模块名称解析为绝对模块名称。

如果 名称 没有前导点,则简单地返回 名称。这允许使用例如 importlib.util.resolve_name('sys', __package__),而不进行检查以查看是否需要 参数。

如果 名称 是相对模块名称,但包是假值(例如 None 或空字符串),则会引发 ValueErrorValueError 也被提出一个相对的名字将逃避其包含的包(例如从 spam 包内请求 ..bacon)。

3.3 新版功能.

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

查找模块的 规格,可选地相对于指定的 名称。如果模块在 sys.modules 中,则返回 sys.modules[name].__spec__ (除非规范将是 None 或未设置,在这种情况下引发 ValueError)。否则,使用 sys.meta_path 的搜索完成。如果没有找到规格,则返回 None

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

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

3.4 新版功能.

importlib.util.module_from_spec(spec)

基于 规格spec.loader.create_module 创建新模块。

如果 spec.loader.create_module 不返回 None,则任何预先存在的属性将不会被重置。此外,如果在访问 规格 或在模块上设置属性时触发,则不会引发 AttributeError

此功能优于使用 types.ModuleType 创建新模块,因为 规格 用于在模块上设置尽可能多的导入控制属性。

3.5 新版功能.

@importlib.util.module_for_loader

decorator 用于 importlib.abc.Loader.load_module() 处理选择要加载的正确模块对象。修饰的方法期望具有采用两个位置参数(例如 load_module(self, module))的调用签名,其中第二参数将是将由加载器使用的模块 目的。注意,装饰器不会在静态方法上工作,因为假设有两个参数。

装饰方法将接收模块的 名称,如对于 loader 所期望的那样被加载。如果在 sys.modules 中找不到该模块,则构造一个新的模块。无论模块来自哪里,__loader__ 设置为 __package__ 基于 importlib.abc.InspectLoader.is_package() 返回(如果可用)设置。这些属性无条件设置以支持重新加载。

如果装饰方法引发异常并且将模块添加到 sys.modules,则模块将被移除,以防止部分初始化的模块在 sys.modules 中保留。如果模块已经在 sys.modules 中,那么它将被单独保留。

在 3.3 版更改: __loader____package__ 会自动设置(如果可能)。

在 3.4 版更改: 无条件地设置 __name____loader__ __package__ 以支持重新加载。

3.4 版后已移除: 导入机制现在直接执行此功能提供的所有功能。

@importlib.util.set_loader

decorator 用于 importlib.abc.Loader.load_module() 在返回的模块上设置 __loader__ 属性。如果属性已经设置,装饰器什么都不做。假设包装方法(即 self)的第一个位置参数是应该设置什么 __loader__

在 3.4 版更改: 如果设置为 None,请设置 __loader__,如同属性不存在一样。

3.4 版后已移除: 进口机械自动处理。

@importlib.util.set_package

decorator 用于 importlib.abc.Loader.load_module() 在返回的模块上设置 __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 版更改: 接受 path-like object

class importlib.util.LazyLoader(loader)

延迟模块的加载器的执行直到模块具有访问的属性的类。

此类 只要 与定义 exec_module() 的装载程序配合使用,用于控制要使用的模块类型。由于同样的原因,加载器的 create_module() 方法必须返回 None 或一个类型,其 __class__ 属性可以随着不使用 插槽 而被突变。最后,替换放置在 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))

31.5.6. 例子

31.5.6.1. 以编程方式导入

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

import importlib

itertools = importlib.import_module('itertools')

31.5.6.2. 检查是否可以导入模块

如果你需要找出一个模块是否可以导入,而不实际导入,那么你应该使用 importlib.util.find_spec()

import importlib.util
import sys

# For illustrative purposes.
name = 'itertools'

spec = importlib.util.find_spec(name)
if spec is None:
    print("can't find the itertools module")
else:
    # If you chose to perform the actual import ...
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    # Adding the module to sys.modules is optional.
    sys.modules[name] = module

31.5.6.3. 直接导入源文件

要直接导入Python源文件,请使用以下配方(仅限Python 3.4和更高版本):

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)
spec.loader.exec_module(module)
# Optional; only necessary if you want to be able to import the module
# by name later.
sys.modules[module_name] = module

31.5.6.4. 设置进口商

对于导入的深度定制,您通常需要实施 importer。这意味着管理东西的 finderloader 两方面。对于发现者,有两种风味可供选择,具体取决于您的需要:meta path finderpath entry finder。前者是你会放在 sys.meta_path,而后者是你使用 path entry hooksys.path_hooks 创建,它使用 sys.path 条目,以潜在地创建一个finder。此示例将显示如何注册自己的导入器,以便导入将使用它们(为自己创建导入器,请阅读此包中定义的适当类的文档):

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

31.5.6.5. 近似 importlib.import_module()

导入本身在Python代码中实现,使得通过importlib暴露大多数导入机制成为可能。下面通过提供 importlib.import_module() 的近似实现(Python 3.4和更新的importlib用法,Python 3.6和更新的代码的其他部分)帮助说明了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:
        raise ImportError(f'No module named {absolute_name!r}')
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    sys.modules[absolute_name] = module
    if path is not None:
        setattr(parent_module, child_name, module)
    return module