31.5. importlib
— The implementation of import
¶
3.1 新版功能.
31.5.1. 概述¶
The purpose of the importlib
package is two-fold. One is to provide the
implementation of the import
statement (and thus, by extension, the
__import__()
function) in Python source code. This provides an
implementation of import
which is portable to any Python
interpreter. This also provides an implementation which is easier to
comprehend than one implemented in a programming language other than Python.
第二个目的是实现 import
的部分被公开在这个包中,使得用户更容易创建他们自己的自定义对象 (通常被称为 importer) 来参与到导入过程中。
参见
- The import statement
import
语句的语言参考- 包规格说明
包的初始规范。自从编写这个文档开始,一些语义已经发生改变了(比如基于
sys.modules
中None
的重定向)。__import__()
函数import
语句是这个函数的语法糖。- PEP 235
在忽略大小写的平台上进行导入
- PEP 263
定义 Python 源代码编码
- PEP 302
新导入钩子
- PEP 328
导入:多行和绝对/相对
- PEP 366
主模块显式相对导入
- PEP 420
隐式命名空间包
- PEP 451
导入系统的一个模块规范类型
- 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
)。如果参数 name 使用相对导入的方式来指定,那么那个参数 packages 必须设置为那个包名,这个包名作为解析这个包名的锚点 (比如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
中的内部缓存无效。如果一个查找器实现了invalidate_caches()
,那么它会被调用来执行那个无效过程。 如果创建/安装任何模块,同时正在运行的程序是为了保证所有的查找器知道新模块的存在,那么应该调用这个函数。3.3 新版功能.
-
importlib.
reload
(module)¶ 重新加载之前导入的 module。那个参数必须是一个模块对象,所以它之前必须已经成功导入了。这样做是有用的,如果使用外部编辑器编已经辑过了那个模块的源代码文件并且想在退出 Python 解释器之前试验这个新版本的模块。函数的返回值是那个模块对象(如果重新导入导致一个不同的对象放置在
sys.modules
中,那么那个模块对象是有可能会不同)。当执行
reload()
的时候:Python 模块的代码会被重新编译并且那个模块级的代码被重新执行,通过重新使用一开始加载那个模块的 loader,定义一个新的绑定在那个模块字典中的名称的对象集合。扩展模块的``init``函数不会被调用第二次。
与Python中的所有的其它对象一样,旧的对象只有在它们的引用计数为0之后才会被回收。
模块命名空间中的名称重新指向任何新的或更改后的对象。
其他旧对象的引用(例如那个模块的外部名称)不会被重新绑定到引用的新对象的,并且如果有需要,必须在出现的每个命名空间中进行更新。
有一些其他注意事项:
当一个模块被重新加载的时候,它的字典(包含了那个模块的全区变量)会被保留。名称的重新定义会覆盖旧的定义,所以通常来说这不是问题。如果一个新模块没有定义在旧版本模块中定义的名称,则将保留旧版本中的定义。这一特性可用于作为那个模块的优点,如果它维护一个全局表或者对象的缓存 —— 使用
try
语句,就可以测试表的存在并且跳过它的初始化,如果有需要的话:try: cache except NameError: cache = {}
重新加载内置的或者动态加载模块,通常来说不是很有用处。不推荐重新加载”
sys
,__main__
,builtins
和其它关键模块。在很多例子中,扩展模块并不是设计为不止一次的初始化,并且当重新加载时,可能会以任意方式失败。If a module imports objects from another module using
from
…import
…, callingreload()
for the other module does not redefine the objects imported from it — one way around this is to re-execute thefrom
statement, another is to useimport
and qualified names (module.name) instead.如果一个模块创建一个类的实例,重新加载定义那个类的模块不影响那些实例的方法定义———它们继续使用旧类中的定义。对于子类来说同样是正确的。
3.4 新版功能.
31.5.3. importlib.abc
—— 关于导入的抽象基类¶
源代码: Lib/importlib/abc.py
The importlib.abc
module contains all of the core abstract base classes
used by import
. Some subclasses of the core abstract base classes
are also provided to help in implementing the core ABCs.
ABC 类的层次结构:
object
+-- Finder (deprecated)
| +-- MetaPathFinder
| +-- PathEntryFinder
+-- Loader
+-- ResourceLoader --------+
+-- InspectLoader |
+-- ExecutionLoader --+
+-- FileLoader
+-- SourceLoader
-
class
importlib.abc.
Finder
¶ 代表 finder 的一个抽象基类
3.3 版后已移除: 使用
MetaPathFinder
或PathEntryFinder
来代替。-
abstractmethod
find_module
(fullname, path=None)¶ 为指定的模块查找 loader 定义的抽象方法。本来是在 PEP 302 指定的,这个方法是在
sys.meta_path
和基于路径的导入子系统中使用。在 3.4 版更改: 当被调用的时候,返回
None
而不是引发NotImplementedError
。
-
abstractmethod
-
class
importlib.abc.
MetaPathFinder
¶ 代表 meta path finder 的一个抽象基类。 为了保持兼容性,这是
Finder
的一个子类。3.3 新版功能.
-
find_spec
(fullname, path, target=None)¶ An abstract method for finding a spec for the specified module. If this is a top-level import, path will be
None
. Otherwise, this is a search for a subpackage or module and path will be the value of__path__
from the parent package. If a spec cannot be found,None
is returned. When passed in,target
is a module object that the finder may use to make a more educated guess about what spec to return.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
()¶ 当被调用的时候,一个可选的方法应该将查找器使用的任何内部缓存进行无效。将在
sys.meta_path
上的所有查找器的缓存进行无效的时候,这个函数被importlib.invalidate_caches()
所使用。在 3.4 版更改: 当方法被调用的时候,方法返回是
None
而不是NotImplemented
。
-
-
class
importlib.abc.
PathEntryFinder
¶ path entry finder 的一个抽象基类。尽管这个基类和
MetaPathFinder
有一些相似之处,但是PathEntryFinder
只在由PathFinder
提供的基于路径导入子系统中使用。这个抽象类是 Finder 的一个子类,仅仅是因为兼容性的原因。3.3 新版功能.
-
find_spec
(fullname, target=None)¶ An abstract method for finding a spec for the specified module. The finder will search for the module only within the path entry to which it is assigned. If a spec cannot be found,
None
is returned. When passed in,target
is a module object that the finder may use to make a more educated guess about what spec to return.3.4 新版功能.
-
find_loader
(fullname)¶ 一个用于在模块中查找一个 loader 的遗留方法。 返回一个
(loader, portion)
的2元组,portion
是一个贡献给命名空间包部分的文件系统位置的序列。 加载器可能是None
,同时正在指定的portion
表示的是贡献给命名空间包的文件系统位置。portion
可以使用一个空列表来表示加载器不是命名空间包的一部分。 如果loader
是None
并且portion
是一个空列表,那么命名空间包中无加载器或者文件系统位置可查找到(即在那个模块中未能找到任何东西)。如果定义了
find_spec()
,则提供了向后兼容的功能。在 3.4 版更改: 返回
(None, [])
而不是引发NotImplementedError
。 当可于提供相应的功能的时候,使用find_spec()
。3.4 版后已移除: 使用
find_spec()
来代替。
-
find_module
(fullname)¶ Finder.find_module`的具体实现,该方法等价于``self.find_loader(fullname)[0]`()
。3.4 版后已移除: 使用
find_spec()
来代替。
-
invalidate_caches
()¶ 当被调用的时候,一个可选的方法应该将查找器使用的任何内部缓存进行无效。当将所有缓存的查找器的缓存进行无效的时候,该函数被
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()
)。加载器应该在模块上面设置几个属性。(要知道当重新加载一个模块的时候,那些属性某部分可以改变):
__name__
模块的名字
__file__
模块数据存储的路径(不是为了内置的模块而设置)
__cached__
被存储或应该被存储的模块的编译版本的路径(当这个属性不恰当的时候不设置)。
__path__
指定在一个包中搜索路径的一个字符串列表。这个属性不在模块上面进行设置。
__package__
模块/包的父包。如果这个模块是最上层的,那么它是一个为空字符串的值。
importlib.util.module_for_loader()
装饰器可以处理__package__
的细节。
__loader__
用来加载那个模块的加载器。
importlib.util.module_for_loader()
装饰器可以处理__package__
的细节。
当
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
异常。
-
abstractmethod
-
class
importlib.abc.
InspectLoader
¶ 一个实现加载器检查模块可选的 PEP 302 协议的 loader 的抽象基类。
-
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 版后已移除: 使用
exec_module()
来代替。
-
-
class
importlib.abc.
ExecutionLoader
¶ 一个继承自
InspectLoader
的抽象基类,当被实现时,帮助一个模块作为脚本来执行。 这个抽象基类表示可选的 PEP 302 协议。-
abstractmethod
get_filename
(fullname)¶ 一个用来为指定模块返回
__file__
的值的抽象方法。如果无路径可用,则引发ImportError
。如果源代码可用,那么这个方法返回源文件的路径,不管是否是用来加载模块的字节码。
在 3.4 版更改: 引发
ImportError
而不是NotImplementedError
。
-
abstractmethod
-
class
importlib.abc.
FileLoader
(fullname, path)¶ 一个继承自
ResourceLoader
和ExecutionLoader
,提供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_data
(path)¶ 读取 path 作为二进制文件并且返回来自它的字节数据。
-
-
class
importlib.abc.
SourceLoader
¶ 一个用于实现源文件(和可选地字节码)加载的抽象基类。这个类继承自
ResourceLoader
和ExecutionLoader
,需要实现:ExecutionLoader.get_filename()
应该是只返回源文件的路径;不支持无源加载。
由这个类定义的抽象方法用来添加可选的字节码文件支持。不实现这些可选的方法(或导致它们引发
NotImplementedError
异常)导致这个加载器只能与源代码一起工作。 实现这些方法允许加载器能与源 和 字节码文件一起工作。不允许只提供字节码的 无源式 加载。字节码文件是通过移除 Python 编译器的解析步骤来加速加载的优化,并且因此没有开放出字节码专用的 API。-
path_stats
(path)¶ 返回一个包含关于指定路径的元数据的
dict
的可选的抽象方法。 支持的字典键有:'mtime'
(必选项): 一个表示源码修改时间的整数或浮点数;'size'
(可选项):源码的字节大小。
字典中任何其他键会被忽略,以允许将来的扩展。 如果不能处理该路径,则会引发
OSError
。3.3 新版功能.
在 3.4 版更改: 引发
OSError
而不是NotImplemented
。
-
path_mtime
(path)¶ 返回指定文件路径修改时间的可选的抽象方法。
3.3 版后已移除: 在有了
path_stats()
的情况下,这个方法被弃用了。 没必要去实现它了,但是为了兼容性,它依然处于可用状态。 如果文件路径不能被处理,则引发OSError
异常。在 3.4 版更改: 引发
OSError
而不是NotImplemented
。
-
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)¶ Concrete implementation of
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.MetaPathFinder
和importlib.abc.InspectLoader
抽象基类。此类只定义类的方法,以减轻实例化的开销。
在 3.5 版更改: 作为 PEP 489 的一部分,现在内置模块导入器实现了
Loader.create_module()
和Loader.exec_module()
。
-
class
importlib.machinery.
FrozenImporter
¶ 用于已冻结模块的 importer。 此类实现了
importlib.abc.MetaPathFinder
和importlib.abc.InspectLoader
抽象基类。此类只定义类的方法,以减轻实例化的开销。
-
class
importlib.machinery.
WindowsRegistryFinder
¶ Finder for modules declared in the Windows registry. This class implements the
importlib.abc.MetaPathFinder
ABC.此类只定义类的方法,以减轻实例化的开销。
3.3 新版功能.
3.6 版后已移除: 改用
site
配置。未来版本的 Python 可能不会默认启用该查找器。
-
class
importlib.machinery.
PathFinder
¶ A Finder for
sys.path
and package__path__
attributes. This class implements theimportlib.abc.MetaPathFinder
ABC.此类只定义类的方法,以减轻实例化的开销。
-
classmethod
find_spec
(fullname, path=None, target=None)¶ 类方法试图在
sys.path
或 path 上为 fullname 指定的模块查找 spec。对于每个路径条目,都会查看sys.path_importer_cache
。如果找到非 False 的对象,则将其用作 path entry finder 来查找要搜索的模块。如果在sys.path_importer_cache
中没有找到条目,那会在sys.path_hooks
检索该路径条目的查找器,找到了则和查到的模块信息一起存入sys.path_importer_cache
。如果查找器没有找到,则缓存中的查找器和模块信息都存为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
()¶ Calls
importlib.abc.PathEntryFinder.invalidate_caches()
on all finders stored insys.path_importer_cache
.
在 3.4 版更改: 调用
sys.path_hooks
中的对象,当前工作目录为''
(即空字符串)。-
classmethod
-
class
importlib.machinery.
FileFinder
(path, *loader_details)¶ importlib.abc.PathEntryFinder
的一个具体实现,它会缓存来自文件系统的结果。参数 path 是查找器负责搜索的目录。
loader_details 参数是数量不定的二元组,每个元组包含加载器及其可识别的文件后缀列表。加载器应为可调用对象,可接受两个参数,即模块的名称和已找到文件的路径。
查找器将按需对目录内容进行缓存,通过对每个模块的检索进行状态统计,验证缓存是否过期。因为缓存的滞后性依赖于操作系统文件系统状态信息的粒度,所以搜索模块、新建文件、然后搜索新文件代表的模块,这会存在竞争状态。如果这些操作的频率太快,甚至小于状态统计的粒度,那么模块搜索将会失败。为了防止这种情况发生,在动态创建模块时,请确保调用
importlib.invalidate_caches()
。3.3 新版功能.
-
path
¶ 查找器将要搜索的路径。
-
invalidate_caches
()¶ 清理内部缓存。
-
classmethod
path_hook
(*loader_details)¶ 一个类方法,返回供
sys.path_hooks
使用的闭包。根据直接给出的路径参数和间接给出的 loader_details,闭包会返回一个FileFinder
的实例。如果给闭包的参数不是已存在的目录,将会触发
ImportError
。
-
-
class
importlib.machinery.
SourceFileLoader
(fullname, path)¶ importlib.abc.SourceLoader
的一个具体实现,该实现子类化了importlib.abc.FileLoader
并提供了其他一些方法的具体实现。3.3 新版功能.
-
name
¶ 该加载器将要处理的模块名称。
-
path
¶ 源文件的路径
-
path_stats
(path)¶
-
set_data
(path, 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
¶ 二进制码文件的路径。
-
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
¶ 扩展模块的路径。
-
is_package
(fullname)¶ 根据
EXTENSION_SUFFIXES
,如果文件路径指向某个包的__init__
模块,则返回True
。
-
get_code
(fullname)¶ 返回
None
,因为扩展模块缺少代码对象。
-
get_source
(fullname)¶ 返回
None
,因为扩展模块没有源代码。
-
-
class
importlib.machinery.
ModuleSpec
(name, loader, *, origin=None, loader_state=None, is_package=None)¶ 关于模块导入系统相关状态的规范。通常这是作为模块的
__spec__
属性暴露出来。 在以下描述中,括号里的名字给出了模块对象中直接可用的属性。比如module.__spec__.origin == module.__file__
。 但是请注意,虽然 值 通常是相等的,但它们可以不同,因为两个对象之间没有进行同步。因此__path__
有可能在运行时做过更新,而这不会自动反映在__spec__.submodule_search_locations
中。3.4 新版功能.
-
name
¶
(
__name__
)一个字符串,表示模块的完全限定名称。
-
loader
¶
(
__loader__
)The loader to use for loading. For namespace packages this should be set to
None
.-
origin
¶
(
__file__
)Name of the place from which the module is loaded, e.g. “builtin” for built-in modules and the filename for modules loaded from source. Normally “origin” should be set, but it may be
None
(the default) which indicates it is unspecified.-
submodule_search_locations
¶
(
__path__
)如果是包(否则为 ),子模块所在位置的字符串列表(否则为
None
)。-
loader_state
¶
依模块不同的额外数据的容器,以供加载过程中使用(或
None
)。-
cached
¶
(
__cached__
)字符串,表示编译后的模块所在位置(或
None
)。-
parent
¶
(
__package__
)(Read-only) Fully-qualified name of the package to which the module belongs as a submodule (or
None
).-
has_location
¶
布尔值,表示模块的“origin”属性是否指向可加载的位置。
-
31.5.5. importlib.util
—— 导入器的工具程序代码¶
本模块包含了帮助构建 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.pyc
。 字符串cpython-32
来自于当前的魔法标签 (参见get_tag()
; 如果sys.implementation.cache_tag
未定义则将会引发NotImplementedError
)。The optimization parameter is used to specify the optimization level of the bytecode file. An empty string represents no optimization, so
/foo/bar/baz.py
with an optimization of''
will result in a bytecode path of/foo/bar/__pycache__/baz.cpython-32.pyc
.None
causes the interpter’s optimization level to be used. Any other value’s string representation being used, so/foo/bar/baz.py
with an optimization of2
will lead to the bytecode path of/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc
. The string representation of optimization can only be alphanumeric, elseValueError
is raised.debug_override 参数已废弃,可用于覆盖系统的
__debug__
值。True
值相当于将 optimization 设为空字符串。False
则相当于*optimization* 设为1
。如果 debug_override 和 optimization 都不为None
,则会触发TypeError
。3.4 新版功能.
在 3.5 版更改: 增加了 optimization 参数,废弃了 debug_override 参数。
在 3.6 版更改: 接受一个 path-like object。
-
importlib.util.
source_from_cache
(path)¶ Given the path to a PEP 3147 file name, return the associated source code file path. For example, if path is
/foo/bar/__pycache__/baz.cpython-32.pyc
the returned path would be/foo/bar/baz.py
. path need not exist, however if it does not conform to PEP 3147 or PEP 488 format, aValueError
is raised. Ifsys.implementation.cache_tag
is not defined,NotImplementedError
is raised.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)¶ 将模块的相对名称解析为绝对名称。
If name has no leading dots, then name is simply returned. This allows for usage such as
importlib.util.resolve_name('sys', __package__)
without doing a check to see if the package argument is needed.ValueError
is raised if name is a relative module name but package is a false value (e.g.None
or the empty string).ValueError
is also raised a relative name would escape its containing package (e.g. requesting..bacon
from within thespam
package).3.3 新版功能.
-
importlib.util.
find_spec
(name, package=None)¶ 查找模块的 spec,可选相对指定的 包 名。如果该模块位于
sys.modules
中,则会返回sys.modules[name].__spec__
(除非 spec为None
或未作设置,这时会触发ValueError
)。否则将用sys.meta_path
进行搜索。若找不到则返回None
。如果 name 为一个子模块(带有一个句点),则会自动导入父级模块。
name 和 package 的用法与
import_module()
相同。3.4 新版功能.
-
importlib.util.
module_from_spec
(spec)¶ 基于 spec 和
spec.loader.create_module
创建一个新模块。如果
spec.loader.create_module
未返回None
,那么先前已存在的属性不会被重置。另外,如果AttributeError
是在访问 spec 或设置模块属性时触发的,则不会触发 。本函数比
types.ModuleType
创建新模块要好,因为用到 spec 模块设置了尽可能多的导入控制属性。3.5 新版功能.
-
@
importlib.util.
module_for_loader
¶ importlib.abc.Loader.load_module()
的一个 decorator,用来选取合适的模块对象以供加载。被装饰方法的签名应带有两个位置参数(如:load_module(self, module)
),其中第二个参数将是加载器用到的模块 对象。请注意,由于假定有两个参数,所以装饰器对静态方法不起作用。装饰的方法将接受要加载的模块的 name,正如 loader 一样。如果在
sys.modules
中没有找到该模块,那么将构造一个新模块。不管模块来自哪里,__loader__
设置为 self ,并且__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
¶ 一个用于
importlib.abc.Loader.load_module()
的 decorator ,以便设置返回模块的__package__
属性。如果__package__
已设置且不为None
,则不会做改动。3.4 版后已移除: 现在导入机制会自动用到本方法。
-
importlib.util.
spec_from_loader
(name, loader, *, origin=None, is_package=None)¶ 一个工厂函数,用于创建基于加载器的
ModuleSpec
实例。 形参的含义与 ModuleSpec 的相同。 该函数会利用当前可用的 loader API,比如InspectLoader.is_package()
,以填充所有缺失的规格信息。3.4 新版功能.
-
importlib.util.
spec_from_file_location
(name, location, *, loader=None, submodule_search_locations=None)¶ 一个工厂函数,用于创建基于文件路径的
ModuleSpec
实例。 缺失的信息将通过利用加载器 API 以及模块将基于文件的隐含条件在 spec 上进行填充。3.4 新版功能.
在 3.6 版更改: 接受一个 path-like object。
-
class
importlib.util.
LazyLoader
(loader)¶ 此类会延迟执行模块加载器,直至该模块有一个属性被访问到。
此类 只 适用于定义了
exec_module()
的加载器,因为需要控制模块的类型。 同理,加载器的create_module()
方法必须返回None
或__class__
属性可被改变且不用 slots 的类型。 最后,用于替换sys.modules
内容的模块将无法工作,因为无法在整个解释器中安全地替换模块的引用;如果检测到这种替换,将触发ValueError
。注解
如果项目对启动时间要求很高,只要模块未被用过,此类能够最小化加载模块的开销。对于启动时间并不重要的项目来说,由于加载过程中产生的错误信息会被暂时搁置,因此强烈不建议使用此类。
3.5 新版功能.
在 3.6 版更改: 开始调用
create_module()
,移除importlib.machinery.BuiltinImporter
和importlib.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))
-
classmethod
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.5 以上版本有效):
import importlib.util
import sys
# For illustrative purposes.
import tokenize
file_path = tokenize.__file__
module_name = tokenize.__name__
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
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。 这意味着得同时管理 finder 和 loader。 根据不同的需求,有两种类型的查找器可供选择: meta path finder 或 path entry finder。 前者应位于 sys.meta_path
之上,而后者是用 path entry hook 在 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))
31.5.6.5. importlib.import_module()
的近似实现¶
导入过程本身是用 Python 代码实现的,这样就能通过 importlib 将大多数导入机制暴露出来。以下代码近似实现了 importlib.import_module()
,以帮助说明 importlib 暴露出来的各种 API (importlib 的用法适用于 Python 3.4 以上版本 ,其他代码适用于 Python 3.6 以上版本)。
import importlib.util
import sys
def import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
sys.modules[absolute_name] = module
if path is not None:
setattr(parent_module, child_name, module)
return module