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. 如果找不到指定的模块,将引发ModuleNotFoundErrorPython 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__.pyparent/one/__init__.pySubsequent imports of parent.two or parent.three will execute parent/two/__init__.py and parent/three/__init__.py respectively.parent.twoparent.three的后续导入将分别执行parent/two/__init__.pyparent/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 sys.path for a top level package) changes.相反,它们使用自定义的iterable类型,如果父包(或顶级包的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.bazIn this case, Python first tries to import foo, then foo.bar, and finally foo.bar.baz. 在本例中,Python首先尝试导入foo,然后是foo.bar,最后是foo.bar.bazIf 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.modulesThis 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将包含foofoo.barfoo.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,则会引发ModuleNotFoundErrorIf 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.以下各节更详细地描述了查找程序和加载程序的协议,包括如何创建和注册新协议以扩展导入机制。

Changed in version 3.4:版本3.4中更改: In previous versions of Python, finders returned loaders directly, whereas now they return module specs which contain loaders. 在Python的早期版本中,查找器直接返回加载器,而现在它们返回包含加载器的模块规范。Loaders are still used during import but have fewer responsibilities.装入器在导入过程中仍在使用,但职责较少。

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. 如果无法处理命名模块,则返回NoneIf sys.meta_path processing reaches the end of its list without returning a spec, then a ModuleNotFoundError is raised. 如果sys.meta_path处理到达其列表的末尾而没有返回规范,则会引发ModuleNotFoundErrorAny 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.bazThe 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__属性,则会引发ModuleNotFoundErrorThe 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 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后,将通过第二次遍历元路径来导入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 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).Python的默认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 find_spec().虽然它将继续工作而不会改变,但只有在finder未实现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 (module.__dict__).如果模块是Python模块(与内置模块或动态加载的扩展相反),则加载程序应在模块的全局名称空间(module.__dict__)中执行模块的代码。

  • If the loader cannot execute the module, it should raise an ImportError, although any other exception raised during exec_module() will be propagated.如果加载程序无法执行该模块,则应引发ImportError,但会传播在exec_module()期间引发的任何其他异常。

In many cases, the finder and loader can be the same object; in such cases the find_spec() method would just return a spec with the loader set to self.在许多情况下,finder和loader可以是同一个对象;在这种情况下,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 to sys.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. 使用任何机制加载子模块时(例如importlibAPI、importimport-from语句或内置的__import__()),会在父模块的命名空间中放置到子模块对象的绑定。For example, if package spam has a submodule foo, after importing spam.foo, spam will have an attribute foo which is bound to the submodule. 例如,如果包spam有一个子模块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:然后执行以下操作将fooFoo的名称绑定放入垃圾邮件模块中:

>>> 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__ attribute on a module object. 模块的spec作为模块对象上的__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 __init__.py files containing only __path__ manipulation code; the import machinery automatically sets __path__ correctly for the namespace package.随着PEP 420的采用,名称空间包不再需要提供只包含__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 not None, 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 __name__ in the repr.否则,只需在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 module_repr() method, if defined, before trying either approach described above. 为了与Python 3.3向后兼容,在尝试上述任一方法之前,将通过调用加载程序的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 module_repr() is slated to stop in Python 3.12.在Python 3.12中,module_repr()的使用将停止。

5.4.7. Cached bytecode invalidation缓存字节码无效

Before Python loads cached bytecode from a .pyc file, it checks whether the cache is up-to-date with the source .py file. 在Python从.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 files: checked and unchecked. 基于哈希的pyc文件有两种变体:checked和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 (.py files), Python byte code (.pyc files) and shared libraries (e.g. .so files). 默认路径条目查找器集实现了在文件系统上查找模块的所有语义,处理特殊的文件类型,如Python源代码(.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.pathsys.path_hookssys.path_importer_cacheThe __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 environment variable and various other installation- and implementation-specific defaults. 它是从PYTHONPATH环境变量和其他各种安装和实现特定的默认值初始化的。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. 此可调用项可能返回可处理路径项的路径项查找器,也可能引发ImportErrorAn 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 ImportError.钩子应该期望字符串或字节对象;字节对象的编码由钩子决定(例如,它可能是文件系统编码、UTF-8或其他内容),如果钩子无法解码参数,则应引发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__() function may be sufficient. 如果只改变import语句的行为而不影响访问导入系统的其他API是可以接受的,那么替换内置的__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就足够了,而不是返回NoneThe 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.pysubpackage1/__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 __main__ module is a special case relative to Python’s import system. 相对于Python的导入系统,__main__模块是一个特例。As noted elsewhere, the __main__ module is directly initialized at interpreter startup, much like sys and builtins. 其他地方所述,__main__模块在解释器启动时直接初始化,很像sysbuiltins模块。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 -m option, __spec__ is set to the module spec of the corresponding module or package. 当Python使用-m选项启动时,__spec__设置为相应模块或包的模块。__spec__ is also populated when the __main__ module is loaded as part of executing a directory, zipfile or other sys.path entry.在执行目录、zipfile或其他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 option

  • running 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 __main__ is initialized?XXX是否添加有关初始化__main__的不同方式的更多说明?

XXX Add more info on __main__ quirks/pitfalls (i.e. copy from PEP 395).XXX添加有关__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 the sys.path_importer_cache. 在旧代码中,可以在sys.path_importer_cache中找到imp.NullImporter的实例。It is recommended that code be changed to use None instead. 建议将代码更改为使用NoneSee Porting Python code for more details.有关更多详细信息,请参阅移植Python代码