5. The import system导入系统¶
Python code in one module gains access to the code in another module by the process of importing it. 一个模块中的Python代码通过导入另一个模块的过程来获得对另一个模块中的代码的访问。The import
statement is the most common way of invoking the import machinery, but it is not the only way. import
语句是调用导入机制的最常用方法,但它不是唯一的方法。Functions such as 诸如importlib.import_module()
and built-in __import__()
can also be used to invoke the import machinery.importlib.import_module()
和内置的__import__()
之类的函数也可以用来调用导入机制。
The import
statement combines two operations; it searches for the named module, then it binds the results of that search to a name in the local scope. import
语句结合了两个操作;它搜索命名模块,然后将搜索结果绑定到本地范围内的名称。The search operation of the import
statement is defined as a call to the __import__()
function, with the appropriate arguments. import
语句的搜索操作被定义为调用带有适当参数的__import__()
函数。The return value of 返回值__import__()
is used to perform the name binding operation of the import
statement. __import__()
用于执行import
语句的名称绑定操作。See the 有关该名称绑定操作的详细信息,请参阅import
statement for the exact details of that name binding operation.import
语句。
A direct call to 直接调用__import__()
performs only the module search and, if found, the module creation operation. __import__()
只执行模块搜索,如果找到,则执行模块创建操作。While certain side-effects may occur, such as the importing of parent packages, and the updating of various caches (including 虽然可能会产生某些副作用,例如导入父包和更新各种缓存(包括sys.modules
), only the import
statement performs a name binding operation.sys.modules
),但只有import
语句执行名称绑定操作。
When an 执行import
statement is executed, the standard builtin __import__()
function is called. import
语句时,将调用标准内置的__import__()
函数。Other mechanisms for invoking the import system (such as 用于调用导入系统的其他机制(如importlib.import_module()
) may choose to bypass __import__()
and use their own solutions to implement import semantics.importlib.import_module()
)可能会选择绕过__import__()
并使用它们自己的解决方案来实现导入语义。
When a module is first imported, Python searches for the module and if found, it creates a module object 1, initializing it. 当第一次导入模块时,Python将搜索该模块,如果找到,它将创建一个模块对象1,并对其进行初始化。If the named module cannot be found, a 如果找不到指定的模块,将引发ModuleNotFoundError
is raised. ModuleNotFoundError
。Python implements various strategies to search for the named module when the import machinery is invoked. Python实现了各种策略,以便在调用导入机制时搜索命名模块。These strategies can be modified and extended by using various hooks described in the sections below.这些策略可以通过使用下面各节中描述的各种挂钩进行修改和扩展。
Changed in version 3.3:版本3.3中更改: The import system has been updated to fully implement the second phase of PEP 302. 已更新导入系统,以全面实施政治PEP 302的第二阶段。There is no longer any implicit import machinery - the full import system is exposed through 不再有任何隐式导入机制-完整的导入系统通过sys.meta_path
. sys.meta_path
公开。In addition, native namespace package support has been implemented (see PEP 420).此外,还实现了对本机命名空间包的支持(请参阅PEP 420)。
5.1. importlib
¶
The importlib
module provides a rich API for interacting with the import system. importlib
模块提供了一个丰富的API,用于与导入系统交互。For example 例如,importlib.import_module()
provides a recommended, simpler API than built-in __import__()
for invoking the import machinery. importlib.import_module()
为调用导入机制提供了一个推荐的、比内置的__import__()
更简单的API。Refer to the 有关更多详细信息,请参阅importlib
library documentation for additional detail.importlib
库文档。
5.2. Packages包装¶
Python has only one type of module object, and all modules are of this type, regardless of whether the module is implemented in Python, C, or something else. Python只有一种类型的模块对象,所有模块都属于这种类型,无论模块是用Python、C还是其他语言实现的。To help organize modules and provide a naming hierarchy, Python has a concept of packages.为了帮助组织模块并提供命名层次结构,Python有一个包的概念。
You can think of packages as the directories on a file system and modules as files within directories, but don’t take this analogy too literally since packages and modules need not originate from the file system. 您可以将包视为文件系统上的目录,将模块视为目录中的文件,但不要将此类比过于字面化,因为包和模块不必源自文件系统。For the purposes of this documentation, we’ll use this convenient analogy of directories and files. 在本文档中,我们将使用目录和文件的这种方便的类比。Like file system directories, packages are organized hierarchically, and packages may themselves contain subpackages, as well as regular modules.与文件系统目录一样,包是按层次结构组织的,包本身可能包含子包以及常规模块。
It’s important to keep in mind that all packages are modules, but not all modules are packages. 请务必记住,所有包都是模块,但并非所有模块都是包。Or put another way, packages are just a special kind of module. 或者换句话说,包只是一种特殊的模块。Specifically, any module that contains a 具体来说,任何包含__path__
attribute is considered a package.__path__
属性的模块都被视为包。
All modules have a name. 所有模块都有一个名称。Subpackage names are separated from their parent package name by a dot, akin to Python’s standard attribute access syntax. 子包名称与父包名称之间用点分隔,类似于Python的标准属性访问语法。Thus you might have a package called 因此,您可能有一个名为email
, which in turn has a subpackage called email.mime
and a module within that subpackage called email.mime.text
.email
的包,该包又有一个名为email.mime
的子包,该子包中有一个名为email.mime.text
的模块。
5.2.1. Regular packages常规包装¶
Python defines two types of packages, regular packages and namespace packages. Python定义了两种类型的包,常规包和命名空间包。Regular packages are traditional packages as they existed in Python 3.2 and earlier. 常规包是Python 3.2及更早版本中存在的传统包。A regular package is typically implemented as a directory containing an 常规包通常实现为包含__init__.py
file. __init__.py
文件的目录。When a regular package is imported, this 导入常规包时,将隐式执行此__init__.py
file is implicitly executed, and the objects it defines are bound to names in the package’s namespace. __init__.py
文件,并将其定义的对象绑定到包命名空间中的名称。The __init__.py
file can contain the same Python code that any other module can contain, and Python will add some additional attributes to the module when it is imported.__init__.py
文件可以包含与任何其他模块相同的Python代码,并且Python将在导入模块时向模块添加一些附加属性。
For example, the following file system layout defines a top level 例如,以下文件系统布局定义了具有三个子包的顶级parent
package with three subpackages:parent
包:
parent/
__init__.py
one/
__init__.py
two/
__init__.py
three/
__init__.py
Importing 导入parent.one
will implicitly execute parent/__init__.py
and parent/one/__init__.py
. parent.one
将隐式执行parent/__init__.py
和parent/one/__init__.py
。Subsequent imports of parent.two
or parent.three
will execute parent/two/__init__.py
and parent/three/__init__.py
respectively.parent.two
或parent.three
的后续导入将分别执行parent/two/__init__.py
和parent/three/__init__.py
。
5.2.2. Namespace packages命名空间包¶
A namespace package is a composite of various portions, where each portion contributes a subpackage to the parent package. 名称空间包是各种部分的组合,其中每个部分为父包提供一个子包。Portions may reside in different locations on the file system. 部分可能位于文件系统上的不同位置。Portions may also be found in zip files, on the network, or anywhere else that Python searches during import. 部分还可以在zip文件、网络或Python在导入期间搜索的任何其他地方找到。Namespace packages may or may not correspond directly to objects on the file system; they may be virtual modules that have no concrete representation.命名空间包可能与文件系统上的对象直接对应,也可能不直接对应;它们可能是没有具体表示的虚拟模块。
Namespace packages do not use an ordinary list for their 命名空间包的__path__
attribute. __path__
属性不使用普通列表。They instead use a custom iterable type which will automatically perform a new search for package portions on the next import attempt within that package if the path of their parent package (or 相反,它们使用自定义的iterable类型,如果父包(或顶级包的sys.path
for a top level package) changes.sys.path
)的路径发生更改,则该类型将在该包内的下一次导入尝试中自动对包部分执行新的搜索。
With namespace packages, there is no 对于命名空间包,没有parent/__init__.py
file. parent/__init__.py
文件。In fact, there may be multiple 事实上,在导入搜索期间可能会找到多个parent
directories found during import search, where each one is provided by a different portion. parent
目录,其中每个parent
目录由不同的部分提供。Thus 因此,parent/one
may not be physically located next to parent/two
. parent/one
可能不会在物理上位于parent/two
旁边。In this case, Python will create a namespace package for the top-level 在这种情况下,每当导入顶级parent
package whenever it or one of its subpackages is imported.parent
包或其子包时,Python都会为其创建一个命名空间包。
See also PEP 420 for the namespace package specification.另请参见PEP 420以了解命名空间包规范。
5.3. Searching搜索¶
To begin the search, Python needs the fully qualified name of the module (or package, but for the purposes of this discussion, the difference is immaterial) being imported. 为了开始搜索,Python需要导入的模块(或包)的完全限定名称,但就本讨论而言,差异并不重要。This name may come from various arguments to the 此名称可能来自import
statement, or from the parameters to the importlib.import_module()
or __import__()
functions.import
语句的各种参数,也可能来自__import__()
函数的参数。
This name will be used in various phases of the import search, and it may be the dotted path to a submodule, e.g. 该名称将用于导入搜索的各个阶段,它可能是指向子模块的虚线路径,例如foo.bar.baz
. foo.bar.baz
。In this case, Python first tries to import 在本例中,Python首先尝试导入foo
, then foo.bar
, and finally foo.bar.baz
. foo
,然后是foo.bar
,最后是foo.bar.baz
。If any of the intermediate imports fail, a 如果任何中间导入失败,将引发ModuleNotFoundError
is raised.ModuleNotFoundError
。
5.3.1. The module cache模块缓存¶
The first place checked during import search is 导入搜索期间检查的第一个位置是sys.modules
. sys.modules
。This mapping serves as a cache of all modules that have been previously imported, including the intermediate paths. 此映射用作以前导入的所有模块的缓存,包括中间路径。So if 因此,如果之前导入了foo.bar.baz
was previously imported, sys.modules
will contain entries for foo
, foo.bar
, and foo.bar.baz
. foo.bar.baz
,那么sys.modules
将包含foo
、foo.bar
和foo.bar.baz
的条目。Each key will have as its value the corresponding module object.每个键都将相应的模块对象作为其值。
During import, the module name is looked up in 在导入期间,将在sys.modules
and if present, the associated value is the module satisfying the import, and the process completes. sys.modules
中查找模块名称,如果存在,则关联的值是满足导入的模块,并且该过程完成。However, if the value is 但是,如果该值为None
, then a ModuleNotFoundError
is raised. None
,则会引发ModuleNotFoundError
。If the module name is missing, Python will continue searching for the module.如果模块名称丢失,Python将继续搜索该模块。
sys.modules
is writable. 是可写的。Deleting a key may not destroy the associated module (as other modules may hold references to it), but it will invalidate the cache entry for the named module, causing Python to search anew for the named module upon its next import. 删除密钥可能不会破坏关联的模块(因为其他模块可能会保存对它的引用),但它会使命名模块的缓存项无效,导致Python在下次导入时重新搜索命名模块。The key can also be assigned to 也可以将该键分配给None
, forcing the next import of the module to result in a ModuleNotFoundError
.None
,从而强制下次导入模块时产生ModuleNotFoundError
。
Beware though, as if you keep a reference to the module object, invalidate its cache entry in 但是要注意,如果您保留对模块对象的引用,在sys.modules
, and then re-import the named module, the two module objects will not be the same. sys.modules
中使其缓存项无效,然后重新导入命名模块,那么这两个模块对象将不同。By contrast, 相反,importlib.reload()
will reuse the same module object, and simply reinitialise the module contents by rerunning the module’s code.importlib.reload()
将重用相同的模块对象,只需通过重新运行模块的代码来重新初始化模块内容。
5.3.2. Finders and loaders查找器和装载器¶
If the named module is not found in 如果在sys.modules
, then Python’s import protocol is invoked to find and load the module. sys.modules
中找不到命名模块,则调用Python的导入协议来查找和加载模块。This protocol consists of two conceptual objects, finders and loaders. 该协议由两个概念对象组成,即查找器和装入器。A finder’s job is to determine whether it can find the named module using whatever strategy it knows about. 查找器的工作是确定它是否可以使用它所知道的任何策略来查找指定模块。Objects that implement both of these interfaces are referred to as importers - they return themselves when they find that they can load the requested module.实现这两个接口的对象称为导入器,当它们发现可以加载请求的模块时,就会返回它们自己。
Python includes a number of default finders and importers. Python包括许多默认查找程序和导入程序。The first one knows how to locate built-in modules, and the second knows how to locate frozen modules. 第一个知道如何定位内置模块,第二个知道如何定位冻结的模块。A third default finder searches an import path for modules. 第三个默认查找器搜索模块的导入路径。The import path is a list of locations that may name file system paths or zip files. 导入路径是可以命名文件系统路径或zip文件的位置列表。It can also be extended to search for any locatable resource, such as those identified by URLs.它还可以扩展到搜索任何可定位的资源,例如由URL标识的资源。
The import machinery is extensible, so new finders can be added to extend the range and scope of module searching.导入机制是可扩展的,因此可以添加新的查找程序来扩展模块搜索的范围和范围。
Finders do not actually load modules. 查找程序实际上并不加载模块。If they can find the named module, they return a module spec, an encapsulation of the module’s import-related information, which the import machinery then uses when loading the module.如果可以找到指定的模块,则返回模块规范,即模块导入相关信息的封装,导入机器在加载模块时使用该信息。
The following sections describe the protocol for finders and loaders in more detail, including how you can create and register new ones to extend the import machinery.以下各节更详细地描述了查找程序和加载程序的协议,包括如何创建和注册新协议以扩展导入机制。
5.3.3. Import hooks导入挂钩¶
The import machinery is designed to be extensible; the primary mechanism for this are the import hooks. 进口机械设计为可扩展;实现这一点的主要机制是导入挂钩。There are two types of import hooks: meta hooks and import path hooks.有两种类型的导入挂钩:元挂钩和导入路径挂钩。
Meta hooks are called at the start of import processing, before any other import processing has occurred, other than 元挂钩在导入处理开始时调用,在任何其他导入处理发生之前调用,sys.modules
cache look up. sys.modules
缓存查找除外。This allows meta hooks to override 这允许元挂钩覆盖sys.path
processing, frozen modules, or even built-in modules. sys.path
处理、冻结模块甚至内置模块。Meta hooks are registered by adding new finder objects to 通过向sys.meta_path
, as described below.sys.meta_path
添加新的finder对象来注册元挂钩,如下所述。
Import path hooks are called as part of 导入路径挂钩作为sys.path
(or package.__path__
) processing, at the point where their associated path item is encountered. sys.path
(或package.__path__
)处理的一部分,在遇到其关联的路径项时调用。Import path hooks are registered by adding new callables to 导入路径挂钩是通过向sys.path_hooks
as described below.sys.path_hooks
添加新的可调用项来注册的,如下所述。
5.3.4. The meta path元路径¶
When the named module is not found in 当在sys.modules
, Python next searches sys.meta_path
, which contains a list of meta path finder objects. sys.modules
中找不到命名模块时,Python接下来将搜索sys.meta_path
,该路径包含元路径查找器对象的列表。These finders are queried in order to see if they know how to handle the named module. 查询这些查找程序是为了查看它们是否知道如何处理命名模块。Meta path finders must implement a method called 元路径查找程序必须实现名为find_spec()
which takes three arguments: a name, an import path, and (optionally) a target module. find_spec()
的方法,该方法接受三个参数:名称、导入路径和(可选)目标模块。The meta path finder can use any strategy it wants to determine whether it can handle the named module or not.元路径查找器可以使用它想要确定是否可以处理命名模块的任何策略。
If the meta path finder knows how to handle the named module, it returns a spec object. 如果元路径查找器知道如何处理命名模块,它将返回一个spec对象。If it cannot handle the named module, it returns 如果无法处理命名模块,则返回None
. None
。If 如果sys.meta_path
processing reaches the end of its list without returning a spec, then a ModuleNotFoundError
is raised. sys.meta_path
处理到达其列表的末尾而没有返回规范,则会引发ModuleNotFoundError
。Any other exceptions raised are simply propagated up, aborting the import process.引发的任何其他异常只会向上传播,从而中止导入过程。
The 使用两个或三个参数调用元路径查找器的find_spec()
method of meta path finders is called with two or three arguments. find_spec()
方法。The first is the fully qualified name of the module being imported, for example 第一个是要导入的模块的完全限定名,例如foo.bar.baz
. foo.bar.baz
。The second argument is the path entries to use for the module search. 第二个参数是用于模块搜索的路径条目。For top-level modules, the second argument is 对于顶级模块,第二个参数是None
, but for submodules or subpackages, the second argument is the value of the parent package’s __path__
attribute. None
,但对于子模块或子包,第二个参数是父包的__path__
属性的值。If the appropriate 如果无法访问相应的__path__
attribute cannot be accessed, a ModuleNotFoundError
is raised. __path__
属性,则会引发ModuleNotFoundError
。The third argument is an existing module object that will be the target of loading later. 第三个参数是一个现有的模块对象,它将成为以后加载的目标。The import system passes in a target module only during reload.导入系统仅在重新加载期间传入目标模块。
The meta path may be traversed multiple times for a single import request. 对于单个导入请求,可以多次遍历元路径。For example, assuming none of the modules involved has already been cached, importing 例如,假设所涉及的模块都没有被缓存,那么导入foo.bar.baz
will first perform a top level import, calling mpf.find_spec("foo", None, None)
on each meta path finder (mpf
). foo.bar.baz
将首先执行顶级导入,在每个元路径查找器(mpf
)上调用mpf.find_spec("foo", None, None)
。After 导入foo后,将通过第二次遍历元路径来导入foo
has been imported, foo.bar
will be imported by traversing the meta path a second time, calling mpf.find_spec("foo.bar", foo.__path__, None)
. foo.bar
,调用mpf.find_spec("foo.bar", foo.__path__, None)
。Once 导入foo.bar
has been imported, the final traversal will call mpf.find_spec("foo.bar.baz", foo.bar.__path__, None)
.foo.bar
后,最终遍历将调用mpf.find_spec("foo.bar.baz", foo.bar.__path__, None)
。
Some meta path finders only support top level imports. 某些元路径查找程序仅支持顶级导入。These importers will always return 当将None
when anything other than None
is passed as the second argument.None
以外的任何内容作为第二个参数传递时,这些导入程序将始终返回None
。
Python’s default Python的默认sys.meta_path
has three meta path finders, one that knows how to import built-in modules, one that knows how to import frozen modules, and one that knows how to import modules from an import path (i.e. the path based finder).sys.meta_path
有三个元路径查找器,一个知道如何导入内置模块,一个知道如何导入冻结模块,还有一个知道如何从导入路径导入模块(即基于路径的查找器)。
Changed in version 3.4:版本3.4中更改: The 元路径查找器的find_spec()
method of meta path finders replaced find_module()
, which is now deprecated. find_spec()
方法替换了find_module()
,后者现在已被弃用。While it will continue to work without change, the import machinery will try it only if the finder does not implement 虽然它将继续工作而不会改变,但只有在finder未实现find_spec()
.find_spec()
时,导入机器才会尝试它。
Changed in version 3.10:版本3.10中更改: Use of 导入系统使用find_module()
by the import system now raises ImportWarning
.find_module()
会引发ImportWarning
。
5.4. Loading¶
If and when a module spec is found, the import machinery will use it (and the loader it contains) when loading the module. 如果找到模块规格,进口机器将在加载模块时使用该规格(及其包含的加载器)。Here is an approximation of what happens during the loading portion of import:以下是导入加载部分期间发生的近似情况:
module = None
if spec.loader is not None and hasattr(spec.loader, 'create_module'):
# It is assumed 'exec_module' will also be defined on the loader.
module = spec.loader.create_module(spec)
if module is None:
module = ModuleType(spec.name)
# The import-related module attributes get set here:
_init_module_attrs(spec, module)
if spec.loader is None:
# unsupported
raise ImportError
if spec.origin is None and spec.submodule_search_locations is not None:
# namespace package
sys.modules[spec.name] = module
elif not hasattr(spec.loader, 'exec_module'):
module = spec.loader.load_module(spec.name)
# Set __loader__ and __package__ if missing.
else:
sys.modules[spec.name] = module
try:
spec.loader.exec_module(module)
except BaseException:
try:
del sys.modules[spec.name]
except KeyError:
pass
raise
return sys.modules[spec.name]
Note the following details:请注意以下详细信息:
If there is an existing module object with the given name in如果sys.modules
, import will have already returned it.sys.modules
中存在具有给定名称的现有模块对象,则import将已返回该对象。
The module will exist in在加载程序执行模块代码之前,模块将存在于sys.modules
before the loader executes the module code.sys.modules
中。This is crucial because the module code may (directly or indirectly) import itself; adding it to这是至关重要的,因为模块代码可能(直接或间接)导入自身;预先将其添加到sys.modules
beforehand prevents unbounded recursion in the worst case and multiple loading in the best.sys.modules
中可以防止在最坏的情况下出现无边界递归,在最好的情况下防止多次加载。
If loading fails, the failing module – and only the failing module – gets removed from如果加载失败,将从sys.modules
.sys.modules
中删除失败的模块,并且仅删除失败的模块。Any module already in the已经在sys.modules
cache, and any module that was successfully loaded as a side-effect, must remain in the cache.sys.modules
缓存中的任何模块以及作为副作用成功加载的任何模块都必须保留在缓存中。This contrasts with reloading where even the failing module is left in这与重新加载形成对比,在重新加载时,即使出现故障的模块也会留在sys.modules
.sys.modules
中。
After the module is created but before execution, the import machinery sets the import-related module attributes (“_init_module_attrs” in the pseudo-code example above), as summarized in a later section.在创建模块之后但在执行之前,导入机制将设置与导入相关的模块属性(上面的伪代码示例中的“_init_module_attrs”),这将在后面的部分中进行总结。
Module execution is the key moment of loading in which the module’s namespace gets populated.模块执行是加载的关键时刻,在此时刻填充模块的命名空间。Execution is entirely delegated to the loader, which gets to decide what gets populated and how.执行完全委托给加载器,加载器决定填充什么以及如何填充。
The module created during loading and passed to exec_module() may not be the one returned at the end of import 2.加载期间创建并传递给exec_module()
的模块可能不是导入2结束时返回的模块。
Changed in version 3.4:版本3.4中更改: The import system has taken over the boilerplate responsibilities of loaders. 进口系统已经接管了装入器的样板责任。These were previously performed by the 这些操作之前是通过importlib.abc.Loader.load_module()
method.importlib.abc.Loader.load_module()
方法执行的。
5.4.1. Loaders装入器¶
Module loaders provide the critical function of loading: module execution. 模块加载器提供加载的关键功能:模块执行。The import machinery calls the 导入机制使用单个参数调用importlib.abc.Loader.exec_module()
method with a single argument, the module object to execute. importlib.abc.Loader.exec_module()
方法,即要执行的模块对象。Any value returned from 从exec_module()
is ignored.exec_module()
返回的任何值都将被忽略。
Loaders must satisfy the following requirements:装入器必须满足以下要求:
If the module is a Python module (as opposed to a built-in module or a dynamically loaded extension), the loader should execute the module’s code in the module’s global name space (如果模块是Python模块(与内置模块或动态加载的扩展相反),则加载程序应在模块的全局名称空间(module.__dict__
).module.__dict__
)中执行模块的代码。
If the loader cannot execute the module, it should raise an如果加载程序无法执行该模块,则应引发ImportError
, although any other exception raised duringexec_module()
will be propagated.ImportError
,但会传播在exec_module()
期间引发的任何其他异常。
In many cases, the finder and loader can be the same object; in such cases the 在许多情况下,finder和loader可以是同一个对象;在这种情况下,find_spec()
method would just return a spec with the loader set to self
.find_spec()
>方法只会返回一个装入器设置为self
的spec。
Module loaders may opt in to creating the module object during loading by implementing a 模块加载器可以通过实现create_module()
method. create_module()
方法选择在加载期间创建模块对象。It takes one argument, the module spec, and returns the new module object to use during loading. 它接受一个参数,即模块规范,并返回要在加载期间使用的新模块对象。create_module()
does not need to set any attributes on the module object. create_module()
不需要在模块对象上设置任何属性。If the method returns 如果该方法返回None
, the import machinery will create the new module itself.None
,导入机制将创建新模块本身。
New in version 3.4.版本3.4中新增。The 装入器的create_module()
method of loaders.create_module()
方法。
Changed in version 3.4:版本3.4中更改: The load_module()
method was replaced by exec_module()
and the import machinery assumed all the boilerplate responsibilities of loading.load_module()
方法被exec_module()
替换,导入机器承担了加载的所有样板责任。
For compatibility with existing loaders, the import machinery will use the 为了与现有装入器兼容,导入机器将使用装入器的load_module()
method of loaders if it exists and the loader does not also implement exec_module()
. load_module()
方法(如果存在),并且装入器未实现exec_module()
。However, 但是,load_module()
has been deprecated and loaders should implement exec_module()
instead.load_module()
已被弃用,加载程序应该实现exec_module()
。
The 除了执行模块外,load_module()
method must implement all the boilerplate loading functionality described above in addition to executing the module. load_module()
方法还必须实现上述所有样板加载功能。All the same constraints apply, with some additional clarification:所有相同的限制条件都适用,但需要进一步澄清:
If there is an existing module object with the given name in如果sys.modules
, the loader must use that existing module.sys.modules
中存在具有给定名称的现有模块对象,则加载程序必须使用该现有模块。(Otherwise,(否则,importlib.reload()
will not work correctly.)importlib.reload()
将无法正常工作。)If the named module does not exist in如果命名模块在sys.modules
, the loader must create a new module object and add it tosys.modules
.sys.modules
中不存在,加载程序必须创建一个新的模块对象并将其添加到sys.modules
中。
The module must exist in在加载程序执行模块代码之前,模块必须存在于sys.modules
before the loader executes the module code, to prevent unbounded recursion or multiple loading.sys.modules
中,以防止无限递归或多次加载。
If loading fails, the loader must remove any modules it has inserted into如果加载失败,加载程序必须删除它插入到sys.modules
, but it must remove only the failing module(s), and only if the loader itself has loaded the module(s) explicitly.sys.modules
中的所有模块,但它必须只删除出现故障的模块,并且只有在加载程序本身显式加载了模块的情况下。
Changed in version 3.5:版本3.5中更改: A 当定义了DeprecationWarning
is raised when exec_module()
is defined but create_module()
is not.exec_module()
但未定义create_module()
时,将引发DeprecationWarning
。
Changed in version 3.6:版本3.6中更改: An 定义了ImportError
is raised when exec_module()
is defined but create_module()
is not.exec_module()
但未定义create_module()
时,将引发ImportError
。
Changed in version 3.10:版本3.10中更改: Use of 使用load_module()
will raise ImportWarning
.load_module()
将引发ImportWarning
。
5.4.2. Submodules子模块¶
When a submodule is loaded using any mechanism (e.g. 使用任何机制加载子模块时(例如importlib
APIs, the import
or import-from
statements, or built-in __import__()
) a binding is placed in the parent module’s namespace to the submodule object. importlib
API、import
或import-from
语句或内置的__import__()
),会在父模块的命名空间中放置到子模块对象的绑定。For example, if package 例如,如果包spam有一个子模块spam
has a submodule foo
, after importing spam.foo
, spam
will have an attribute foo
which is bound to the submodule. foo
,则导入spamfoo后,spam
将有一个绑定到子模块的属性foo。Let’s say you have the following directory structure:假设您有以下目录结构:
spam/
__init__.py
foo.py
and spam/__init__.py
has the following line in it:spam/__init__.py
中有以下行:
from .foo import Foo
then executing the following puts name bindings for 然后执行以下操作将foo
and Foo
in the spam
module:foo
和Foo
的名称绑定放入垃圾邮件模块中:
>>> import spam
>>> spam.foo
<module 'spam.foo' from '/tmp/imports/spam/foo.py'>
>>> spam.Foo
<class 'spam.foo.Foo'>
Given Python’s familiar name binding rules this might seem surprising, but it’s actually a fundamental feature of the import system. 考虑到Python熟悉的名称绑定规则,这可能看起来很奇怪,但实际上这是导入系统的一个基本特性。The invariant holding is that if you have 不变的保留是,如果您有sys.modules['spam']
and sys.modules['spam.foo']
(as you would after the above import), the latter must appear as the foo
attribute of the former.sys.modules['spam']
和sys.modules['spam.foo']
(正如您在上述导入之后所做的那样),则后者必须显示为前者的foo
属性。
5.4.3. Module spec模块规格¶
The import machinery uses a variety of information about each module during import, especially before loading. 导入机器在导入过程中,尤其是在加载之前,使用有关每个模块的各种信息。Most of the information is common to all modules. 大多数信息对于所有模块都是通用的。The purpose of a module’s spec is to encapsulate this import-related information on a per-module basis.模块规范的目的是在每个模块的基础上封装此导入相关信息。
Using a spec during import allows state to be transferred between import system components, e.g. between the finder that creates the module spec and the loader that executes it. 在导入期间使用规范允许在导入系统组件之间传输状态,例如,在创建模块规范的查找器和执行模块规范的加载程序之间传输状态。Most importantly, it allows the import machinery to perform the boilerplate operations of loading, whereas without a module spec the loader had that responsibility.最重要的是,它允许进口机械执行装载的样板操作,而没有模块规范,装入器就有这一责任。
The module’s spec is exposed as the 模块的spec作为模块对象上的__spec__
attribute on a module object. __spec__
属性公开。See 有关模块规范内容的详细信息,请参阅ModuleSpec
for details on the contents of the module spec.ModuleSpec
。
New in version 3.4.版本3.4中新增。
5.4.5. module.__path__¶
By definition, if a module has a 根据定义,如果模块具有__path__
attribute, it is a package.__path__
属性,则它是一个包。
A package’s 在导入其子包期间,将使用包的__path__
attribute is used during imports of its subpackages. __path__
属性。Within the import machinery, it functions much the same as 在导入机制中,它的功能与sys.path
, i.e. providing a list of locations to search for modules during import. sys.path
非常相似,即提供一个位置列表,以便在导入期间搜索模块。However, 然而,__path__
is typically much more constrained than sys.path
.__path__
通常比sys.path
约束得多。
__path__
must be an iterable of strings, but it may be empty. 必须是字符串的iterable,但它可能为空。The same rules used for sys.path
also apply to a package’s __path__
, and sys.path_hooks
(described below) are consulted when traversing a package’s __path__
.sys.path
使用的相同规则也适用于包的__path__
,在遍历包的__path__
时,会参考sys.path_hooks
(如下所述)。
A package’s 包的__init__.py
file may set or alter the package’s __path__
attribute, and this was typically the way namespace packages were implemented prior to PEP 420. __init__.py
文件可以设置或更改包的__path__
属性,这通常是在PEP 420之前实现命名空间包的方式。With the adoption of PEP 420, namespace packages no longer need to supply 随着PEP 420的采用,名称空间包不再需要提供只包含__init__.py
files containing only __path__
manipulation code; the import machinery automatically sets __path__
correctly for the namespace package.__path__
操作代码的__init__.py
文件;导入机制会自动为命名空间包正确设置__path__
。
5.4.6. Module reprs模块报告¶
By default, all modules have a usable repr, however depending on the attributes set above, and in the module’s spec, you can more explicitly control the repr of module objects.默认情况下,所有模块都有一个可用的repr,但是,根据上面设置的属性,在模块的规范中,您可以更明确地控制模块对象的repr。
If the module has a spec (如果模块有一个规范(__spec__
), the import machinery will try to generate a repr from it. __spec__
),导入机器将尝试从中生成一个repr。If that fails or there is no spec, the import system will craft a default repr using whatever information is available on the module. 如果失败或没有规范,导入系统将使用模块上可用的任何信息创建默认repr。It will try to use the 它将尝试使用该module.__name__
, module.__file__
, and module.__loader__
as input into the repr, with defaults for whatever information is missing.module.__name__
,module.__file__
和module.__loader__
作为repr的输入,默认为缺少的任何信息。
Here are the exact rules used:以下是使用的确切规则:
If the module has a如果模块具有__spec__
attribute, the information in the spec is used to generate the repr.__spec__
属性,则spec中的信息用于生成repr。The “name”, “loader”, “origin”, and “has_location” attributes are consulted.查询“name”、“loader”、“origin”和“has_location”属性。
If the module has a如果模块具有__file__
attribute, this is used as part of the module’s repr.__file__
属性,则该属性将用作模块repr的一部分。
If the module has no如果模块没有__file__
but does have a__loader__
that is notNone
, then the loader’s repr is used as part of the module’s repr.__file__
,但确实有一个不是None
的__loader__
,则加载程序的repr将用作模块repr的一部分。
Otherwise, just use the module’s否则,只需在repr中使用模块的__name__
in the repr.__name__
即可。
Changed in version 3.4:版本3.4中更改: Use of loader.module_repr()
has been deprecated and the module spec is now used by the import machinery to generate a module repr.loader.module_repr()
的使用已被弃用,导入机器现在使用模块规范来生成模块repr。
For backward compatibility with Python 3.3, the module repr will be generated by calling the loader’s 为了与Python 3.3向后兼容,在尝试上述任一方法之前,将通过调用加载程序的module_repr()
method, if defined, before trying either approach described above. module_repr()
方法(如果已定义)来生成模块repr。However, the method is deprecated.但是,该方法已被弃用。
Changed in version 3.10:版本3.10中更改: Calling 现在,在尝试使用模块的module_repr()
now occurs after trying to use a module’s __spec__
attribute but before falling back on __file__
. __spec__
属性之后,但在返回到__file__
之前,调用module_repr()
。Use of 在Python 3.12中,module_repr()
is slated to stop in Python 3.12.module_repr()
的使用将停止。
5.4.7. Cached bytecode invalidation缓存字节码无效¶
Before Python loads cached bytecode from a 在Python从.pyc
file, it checks whether the cache is up-to-date with the source .py
file. .pyc
文件加载缓存的字节码之前,它会检查缓存是否与源.py
文件是最新的。By default, Python does this by storing the source’s last-modified timestamp and size in the cache file when writing it. 默认情况下,Python通过在写入缓存文件时将源的上次修改的时间戳和大小存储在缓存文件中来实现这一点。At runtime, the import system then validates the cache file by checking the stored metadata in the cache file against the source’s metadata.在运行时,导入系统通过检查缓存文件中存储的元数据与源元数据来验证缓存文件。
Python also supports “hash-based” cache files, which store a hash of the source file’s contents rather than its metadata. Python还支持“基于哈希”的缓存文件,它存储源文件内容的哈希,而不是其元数据。There are two variants of hash-based 基于哈希的pyc文件有两种变体:checked和unchecked。.pyc
files: checked and unchecked. For checked hash-based 对于已检查的基于哈希的.pyc
files, Python validates the cache file by hashing the source file and comparing the resulting hash with the hash in the cache file. .pyc
文件,Python通过对源文件进行哈希处理并将结果哈希与缓存文件中的哈希进行比较来验证缓存文件。If a checked hash-based cache file is found to be invalid, Python regenerates it and writes a new checked hash-based cache file. 如果发现基于检查哈希的缓存文件无效,Python将重新生成该文件并写入一个新的基于检查哈希的缓存文件。For unchecked hash-based 对于未经检查的基于哈希的.pyc
files, Python simply assumes the cache file is valid if it exists. .pyc
文件,Python仅假设缓存文件存在时有效。Hash-based 基于散列的.pyc
files validation behavior may be overridden with the --check-hash-based-pycs
flag..pyc
文件验证行为可以用基于散列的--check-hash-based-pycs
标志覆盖。
Changed in version 3.7:版本3.7中更改: Added hash-based 添加了基于哈希的.pyc
files. .pyc
文件。Previously, Python only supported timestamp-based invalidation of bytecode caches.以前,Python只支持基于时间戳的字节码缓存失效。
5.5. The Path Based Finder基于路径的查找器¶
As mentioned previously, Python comes with several default meta path finders. 如前所述,Python附带了几个默认的元路径查找器。One of these, called the path based finder (其中一种称为基于路径的查找器(PathFinder
), searches an import path, which contains a list of path entries. PathFinder
),它搜索导入路径,其中包含路径条目列表。Each path entry names a location to search for modules.每个路径条目指定一个位置以搜索模块。
The path based finder itself doesn’t know how to import anything. 基于路径的查找器本身不知道如何导入任何内容。Instead, it traverses the individual path entries, associating each of them with a path entry finder that knows how to handle that particular kind of path.相反,它遍历各个路径条目,将它们与知道如何处理特定类型路径的路径条目查找器相关联。
The default set of path entry finders implement all the semantics for finding modules on the file system, handling special file types such as Python source code (默认路径条目查找器集实现了在文件系统上查找模块的所有语义,处理特殊的文件类型,如Python源代码(.py
files), Python byte code (.pyc
files) and shared libraries (e.g. .so
files). .py
文件)、Python字节码(.pyc
文件)和共享库(例如.so
文件)。When supported by the 当标准库中的zipimport
module in the standard library, the default path entry finders also handle loading all of these file types (other than shared libraries) from zipfiles.zipimport
模块支持时,默认路径条目查找器还处理从ZipFile加载所有这些文件类型(共享库除外)。
Path entries need not be limited to file system locations. 路径条目不必限于文件系统位置。They can refer to URLs, database queries, or any other location that can be specified as a string.它们可以引用URL、数据库查询或任何其他可以指定为字符串的位置。
The path based finder provides additional hooks and protocols so that you can extend and customize the types of searchable path entries. 基于路径的查找器提供了额外的挂钩和协议,以便您可以扩展和自定义可搜索路径条目的类型。For example, if you wanted to support path entries as network URLs, you could write a hook that implements HTTP semantics to find modules on the web. 例如,如果希望支持路径条目作为网络URL,可以编写一个实现HTTP语义的钩子来查找web上的模块。This hook (a callable) would return a path entry finder supporting the protocol described below, which was then used to get a loader for the module from the web.这个钩子(一个可调用的钩子)将返回一个支持下面描述的协议的路径条目查找器,然后使用它从web获取模块的加载程序。
A word of warning: this section and the previous both use the term finder, distinguishing between them by using the terms meta path finder and path entry finder. 警告:本节和前一节都使用术语查找器,通过使用术语元路径查找器和路径条目查找器来区分它们。These two types of finders are very similar, support similar protocols, and function in similar ways during the import process, but it’s important to keep in mind that they are subtly different. 这两种类型的查找器非常相似,支持类似的协议,并且在导入过程中以类似的方式运行,但重要的是要记住它们有细微的不同。In particular, meta path finders operate at the beginning of the import process, as keyed off the 特别是,元路径查找器在导入过程的开始操作,就像在sys.meta_path
traversal.sys.meta_path
遍历中键入的那样。
By contrast, path entry finders are in a sense an implementation detail of the path based finder, and in fact, if the path based finder were to be removed from 相反,路径条目查找器在某种意义上是基于路径的查找器的实现细节,事实上,如果从sys.meta_path
, none of the path entry finder semantics would be invoked.sys.meta_path
中删除基于路径的查找器,则不会调用任何路径条目查找器语义。
5.5.1. Path entry finders路径入口查找器¶
The path based finder is responsible for finding and loading Python modules and packages whose location is specified with a string path entry. 基于路径的查找器负责查找和加载Python模块和包,这些模块和包的位置由字符串路径条目指定。Most path entries name locations in the file system, but they need not be limited to this.大多数路径条目都会命名文件系统中的位置,但它们不必限于此。
As a meta path finder, the path based finder implements the 作为元路径查找器,基于路径的查找器实现了前面描述的find_spec()
protocol previously described, however it exposes additional hooks that can be used to customize how modules are found and loaded from the import path.find_spec()
协议,但是它公开了其他挂钩,可用于自定义如何从导入路径查找和加载模块。
Three variables are used by the path based finder, 基于路径的查找器使用三个变量:sys.path
, sys.path_hooks
and sys.path_importer_cache
. sys.path
、sys.path_hooks
和sys.path_importer_cache
。The 还使用包对象上的__path__
attributes on package objects are also used. __path__
属性。These provide additional ways that the import machinery can be customized.这些提供了定制进口机械的其他方式。
sys.path
contains a list of strings providing search locations for modules and packages. 包含提供模块和包的搜索位置的字符串列表。It is initialized from the 它是从PYTHONPATH环境变量和其他各种安装和实现特定的默认值初始化的。PYTHONPATH
environment variable and various other installation- and implementation-specific defaults. Entries in sys.path
can name directories on the file system, zip files, and potentially other “locations” (see the site
module) that should be searched for modules, such as URLs, or database queries. sys.path
中的条目可以命名文件系统上的目录、zip文件以及可能需要搜索模块的其他“位置”(请参阅site
模块),例如URL或数据库查询。Only strings and bytes should be present on sys.path
; all other data types are ignored.sys.path
上只应存在字符串和字节;忽略所有其他数据类型。 The encoding of bytes entries is determined by the individual path entry finders.字节条目的编码由各个路径条目查找器确定。
The path based finder is a meta path finder, so the import machinery begins the import path search by calling the path based finder’s 基于路径的查找器是元路径查找器,因此导入机器通过调用基于路径的查找器的find_spec()
method as described previously. find_spec()
方法开始导入路径搜索,如前所述。When the 当给定path
argument to find_spec()
is given, it will be a list of string paths to traverse - typically a package’s __path__
attribute for an import within that package. find_spec()
的path
参数时,它将是一个要遍历的字符串路径列表,通常是该包中导入的包的__path__
属性。If the 如果path
argument is None
, this indicates a top level import and sys.path
is used.path
参数为None
,则表示使用顶级导入和sys.path
。
The path based finder iterates over every entry in the search path, and for each of these, looks for an appropriate path entry finder (基于路径的查找器迭代搜索路径中的每个条目,并为每个条目查找路径条目的适当路径条目查找器(PathEntryFinder
) for the path entry. PathEntryFinder
)。Because this can be an expensive operation (e.g. there may be stat() call overheads for this search), the path based finder maintains a cache mapping path entries to path entry finders. 由于这可能是一个昂贵的操作(例如,此搜索可能会有stat()
调用开销),因此基于路径的查找程序会维护一个将路径条目映射到路径条目查找程序的缓存。This cache is maintained in 此缓存在sys.path_importer_cache
(despite the name, this cache actually stores finder objects rather than being limited to importer objects). sys.path_importer_cache
中维护(尽管名称不同,但此缓存实际上存储查找器对象,而不是仅限于导入器对象)。In this way, the expensive search for a particular path entry location’s path entry finder need only be done once. 这样,对特定路径输入条目位置的路径输入查找器的昂贵搜索只需执行一次。User code is free to remove cache entries from 用户代码可以从sys.path_importer_cache
forcing the path based finder to perform the path entry search again 3.sys.path_importer_cache
中自由删除缓存项,强制基于路径的查找器再次执行路径项搜索3。
If the path entry is not present in the cache, the path based finder iterates over every callable in 如果缓存中不存在路径条目,则基于路径的查找器将迭代sys.path_hooks
. sys.path_hooks
中的每个可调用项。Each of the path entry hooks in this list is called with a single argument, the path entry to be searched. 此列表中的每个路径条目挂钩都用一个参数调用,即要搜索的路径条目。This callable may either return a path entry finder that can handle the path entry, or it may raise 此可调用项可能返回可处理路径项的路径项查找器,也可能引发ImportError
. ImportError
。An 基于路径的查找器使用ImportError
is used by the path based finder to signal that the hook cannot find a path entry finder for that path entry. ImportError
来表示挂钩无法找到该路径条目的路径条目查找器。The exception is ignored and import path iteration continues. 将忽略该异常,并继续导入路径迭代。The hook should expect either a string or bytes object; the encoding of bytes objects is up to the hook (e.g. it may be a file system encoding, UTF-8, or something else), and if the hook cannot decode the argument, it should raise 钩子应该期望字符串或字节对象;字节对象的编码由钩子决定(例如,它可能是文件系统编码、UTF-8或其他内容),如果钩子无法解码参数,则应引发ImportError
.ImportError
。
If 如果sys.path_hooks
iteration ends with no path entry finder being returned, then the path based finder’s find_spec()
method will store None
in sys.path_importer_cache
(to indicate that there is no finder for this path entry) and return None
, indicating that this meta path finder could not find the module.sys.path_hooks
迭代结束时没有返回任何路径条目查找器,则基于路径的查找器的find_spec()
方法将在sys.path_importer_cache
中存储None
(表示此路径条目没有查找器),并返回None
,表示此元路径查找器找不到模块。
If a path entry finder is returned by one of the path entry hook callables on 如果路径条目查找器由sys.path_hooks
, then the following protocol is used to ask the finder for a module spec, which is then used when loading the module.sys.path_hooks
上的路径条目挂钩调用之一返回,则使用以下协议向查找器请求模块规范,然后在加载模块时使用该规范。
The current working directory – denoted by an empty string – is handled slightly differently from other entries on 当前工作目录(由空字符串表示)的处理方式与sys.path
. sys.path
上的其他条目略有不同。First, if the current working directory is found to not exist, no value is stored in 首先,如果发现当前工作目录不存在,sys.path_importer_cache
. sys.path_importer_cache
缓存中不会存储任何值。Second, the value for the current working directory is looked up fresh for each module lookup. 其次,对于每个模块查找,都会新查找当前工作目录的值。Third, the path used for 第三,sys.path_importer_cache
and returned by importlib.machinery.PathFinder.find_spec()
will be the actual current working directory and not the empty string.importlib.machinery.PathFinder.find_spec()
返回的sys.path_importer_cache
使用的路径将是实际的当前工作目录,而不是空字符串。
5.5.2. Path entry finder protocol路径入口查找器协议¶
In order to support imports of modules and initialized packages and also to contribute portions to namespace packages, path entry finders must implement the 为了支持模块和初始化包的导入,并为命名空间包提供部分内容,路径条目查找器必须实现find_spec()
method.find_spec()
方法。
find_spec()
takes two arguments: the fully qualified name of the module being imported, and the (optional) target module. 接受两个参数:要导入的模块的完全限定名和(可选)目标模块。find_spec()
returns a fully populated spec for the module. 返回模块的完全填充规范。This spec will always have “loader” set (with one exception).此规范将始终设置“loader”(加载程序)(只有一个例外)。
To indicate to the import machinery that the spec represents a namespace portion, the path entry finder sets “submodule_search_locations” to a list containing the portion.为了向导入机器指示规范表示名称空间部分,路径条目查找器将“submodule_search_locations”设置为包含该部分的列表。
Changed in version 3.4:版本3.4中更改: find_spec()
replaced find_loader()
and find_module()
, both of which are now deprecated, but will be used if find_spec()
is not defined.find_spec()
替换了find_loader()
和find_module()
,两者现在都已弃用,但如果未定义find_spec()
,则将使用它们。
Older path entry finders may implement one of these two deprecated methods instead of 旧的路径条目查找程序可能会实现这两种不推荐使用的方法之一,而不是find_spec()
. find_spec()
。The methods are still respected for the sake of backward compatibility. 为了向后兼容,仍然尊重这些方法。However, if 但是,如果在路径条目查找器上实现find_spec()
is implemented on the path entry finder, the legacy methods are ignored.find_spec()
,则会忽略旧方法。
find_loader()
takes one argument, the fully qualified name of the module being imported. 接受一个参数,即要导入的模块的完全限定名。find_loader()
returns a 2-tuple where the first item is the loader and the second item is a namespace portion.返回一个2元组,其中第一项是加载程序,第二项是命名空间部分。
For backwards compatibility with other implementations of the import protocol, many path entry finders also support the same, traditional 为了向后兼容导入协议的其他实现,许多路径条目查找器还支持元路径查找器支持的相同的传统find_module()
method that meta path finders support. find_module()
方法。However path entry finder 但是路径条目查找器find_module()
methods are never called with a path
argument (they are expected to record the appropriate path information from the initial call to the path hook).find_module()
方法从不使用path
参数调用(它们应该记录对路径挂钩的初始调用中的适当路径信息)。
The 不推荐使用路径条目查找器上的find_module()
method on path entry finders is deprecated, as it does not allow the path entry finder to contribute portions to namespace packages. find_module()
方法,因为它不允许路径条目查找器将部分内容贡献给命名空间包。If both 如果路径条目查找器上同时存在find_loader()
and find_module()
exist on a path entry finder, the import system will always call find_loader()
in preference to find_module()
.find_loader()
和find_module()
,则导入系统将始终优先调用find_loader()
来引用find_module()
。
Changed in version 3.10:版本3.10中更改: Calls to 导入系统调用find_module()
and find_loader()
by the import system will raise ImportWarning
.find_module()
和find_loader()
将引发ImportWarning
。
5.6. Replacing the standard import system替换标准导入系统¶
The most reliable mechanism for replacing the entire import system is to delete the default contents of 替换整个导入系统最可靠的机制是删除sys.meta_path
, replacing them entirely with a custom meta path hook.sys.meta_path
的默认内容,并用自定义元路径挂钩完全替换它们。
If it is acceptable to only alter the behaviour of import statements without affecting other APIs that access the import system, then replacing the builtin 如果只改变import语句的行为而不影响访问导入系统的其他API是可以接受的,那么替换内置的__import__()
function may be sufficient. __import__()
函数就足够了。This technique may also be employed at the module level to only alter the behaviour of import statements within that module.此技术也可以在模块级别使用,以仅更改该模块内导入语句的行为。
To selectively prevent the import of some modules from a hook early on the meta path (rather than disabling the standard import system entirely), it is sufficient to raise 为了有选择地防止在元路径的早期从钩子导入某些模块(而不是完全禁用标准导入系统),直接从ModuleNotFoundError
directly from find_spec()
instead of returning None
. find_spec()
引发ModuleNotFoundError
就足够了,而不是返回None
。The latter indicates that the meta path search should continue, while raising an exception terminates it immediately.后者表示元路径搜索应该继续,而引发异常会立即终止它。
5.7. Package Relative Imports打包相对导入¶
Relative imports use leading dots. 相对导入使用前导点。A single leading dot indicates a relative import, starting with the current package. 单个前导点表示相对导入,从当前包开始。Two or more leading dots indicate a relative import to the parent(s) of the current package, one level per dot after the first. 两个或多个前导点表示对当前包的父级的相对导入,第一个点后每个点一个级别。For example, given the following package layout:例如,给定以下包布局:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
In either 在subpackage1/moduleX.py
or subpackage1/__init__.py
, the following are valid relative imports:subpackage1/moduleX.py
或subpackage1/__init__.py
中,以下是有效的相对导入:
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
Absolute imports may use either the 绝对导入可以使用import <>
or from <> import <>
syntax, but relative imports may only use the second form; the reason for this is that:import <>
或from <> import <>
语法,但相对导入只能使用第二种形式;原因是:
import XXX.YYY.ZZZ
should expose 应将XXX.YYY.ZZZ
as a usable expression, but .moduleY is not a valid expression.XXX.YYY.ZZZ
作为可用表达式公开,但.moduleY不是有效表达式。
5.8. Special considerations for __main____main__
的特殊注意事项¶
The 相对于Python的导入系统,__main__
module is a special case relative to Python’s import system. __main__
模块是一个特例。As noted elsewhere, the 如其他地方所述,__main__
module is directly initialized at interpreter startup, much like sys
and builtins
. __main__
模块在解释器启动时直接初始化,很像sys
和builtins
模块。However, unlike those two, it doesn’t strictly qualify as a built-in module. 然而,与这两个模块不同,它并没有严格限定为内置模块。This is because the manner in which 这是因为初始化__main__
is initialized depends on the flags and other options with which the interpreter is invoked.__main__
的方式取决于调用解释器的标志和其他选项。
5.8.1. __main__.__spec__¶
Depending on how 取决于__main__
is initialized, __main__.__spec__
gets set appropriately or to None
.__main__
的初始化方式,__main__.__spec__
正确设置或设置为None
。
When Python is started with the 当Python使用-m
option, __spec__
is set to the module spec of the corresponding module or package. -m
选项启动时,__spec__
设置为相应模块或包的模块。在执行目录、zipfile或其他__spec__
is also populated when the __main__
module is loaded as part of executing a directory, zipfile or other sys.path
entry.sys.path
条目时加载__main__
模块时,也会填充__spec__
。
In the remaining cases 在其余情况下,__main__.__spec__
is set to None
, as the code used to populate the __main__
does not correspond directly with an importable module:__main__.__spec__
设置为None
,因为用于填充__main__
的代码与可导入模块不直接对应:
interactive prompt交互式提示-c
optionrunning from stdin从stdin运行running directly from a source or bytecode file直接从源文件或字节码文件运行
Note that 请注意在最后一种情况下,__main__.__spec__
is always None
in the last case, even if the file could technically be imported directly as a module instead. __main__.__spec__
始终为None
,即使文件在技术上可以直接作为模块导入。Use the 如果在-m
switch if valid module metadata is desired in __main__
.__main__
中需要有效的模块元数据,请使用-m
开关。
Note also that even when 还要注意的是,即使当__main__
corresponds with an importable module and __main__.__spec__
is set accordingly, they’re still considered distinct modules. __main__
与可导入模块相对应并且__main__.__spec__
是相应设置的,它们仍然被视为不同的模块。This is due to the fact that blocks guarded by 这是因为由if __name__ == "__main__":
checks only execute when the module is used to populate the __main__
namespace, and not during normal import.if __name__ == "__main__":
保护的块,检查仅在模块用于填充__main__
命名空间时执行,而不是在正常导入期间执行。
5.9. Open issues未解决的问题¶
XXX It would be really nice to have a diagram.有一张图表真的很好。
XXX * (import_machinery.rst) how about a section devoted just to the attributes of modules and packages, perhaps expanding upon or supplanting the related entries in the data model reference page?(import_machineryrst)一节专门介绍模块和包的属性,或者扩展或替换数据模型参考页中的相关条目,怎么样?
XXX runpy, pkgutil, et al in the library manual should all get “See Also” links at the top pointing to the new import system section.库手册中的XXX runpy、pkgutil等都应该在顶部获得指向新导入系统部分的“另请参阅”链接。
XXX Add more explanation regarding the different ways in which XXX是否添加有关初始化__main__
is initialized?__main__
的不同方式的更多说明?
XXX Add more info on XXX添加有关__main__
quirks/pitfalls (i.e. copy from PEP 395).__main__
怪癖/陷阱的更多信息(即从PEP 395复制)。
5.10. References参考¶
The import machinery has evolved considerably since Python’s early days. 自Python早期以来,导入机制已经有了很大的发展。The original specification for packages is still available to read, although some details have changed since the writing of that document.包的原始规范仍然可以阅读,尽管自编写该文档以来,一些细节已经发生了变化。
The original specification for sys.meta_path
was PEP 302, with subsequent extension in PEP 420.sys.meta_path
的原始规范是PEP 302,随后在PEP 420中进行了扩展。
PEP 420 introduced namespace packages for Python 3.3. 介绍了Python 3.3的命名空间包。PEP 420 also introduced the 还引入了find_loader()
protocol as an alternative to find_module()
.find_loader()
协议作为find_module()
的替代协议。
PEP 366 describes the addition of the 描述为主模块中的显式相对导入添加__package__
attribute for explicit relative imports in main modules.__package__
属性。
PEP 328 introduced absolute and explicit relative imports and initially proposed 引入了绝对和显式的相对导入,并最初为语义提出了__name__
for semantics PEP 366 would eventually specify for __package__
.__name__
,PEP 366最终将为__package__
指定。
PEP 338 defines executing modules as scripts.将执行模块定义为脚本。
PEP 451 adds the encapsulation of per-module import state in spec objects. 在等级库对象中添加每个模块导入状态的封装。It also off-loads most of the boilerplate responsibilities of loaders back onto the import machinery. 它还将装载机的大部分样板责任卸回到进口机械上。These changes allow the deprecation of several APIs in the import system and also addition of new methods to finders and loaders.这些更改允许在导入系统中弃用几个API,还允许向查找程序和加载程序添加新方法。
Footnotes
- 1
See
types.ModuleType
.- 2
The importlib implementation avoids using the return value directly.importlib实现避免了直接使用返回值。Instead, it gets the module object by looking the module name up in相反,它通过在sys.modules
.sys.modules
中查找模块名称来获取模块对象。The indirect effect of this is that an imported module may replace itself in这样做的间接影响是,导入的模块可能会在sys.modules
.sys.modules
中替换自身。This is implementation-specific behavior that is not guaranteed to work in other Python implementations.这是特定于实现的行为,不能保证在其他Python实现中工作。- 3
In legacy code, it is possible to find instances of在旧代码中,可以在imp.NullImporter
in thesys.path_importer_cache
.sys.path_importer_cache
中找到imp.NullImporter
的实例。It is recommended that code be changed to use建议将代码更改为使用None
instead.None
。See Porting Python code for more details.有关更多详细信息,请参阅移植Python代码。