5. Система импорта¶
Код Python в одном модуле получает доступ к коду в другом модуле в процессе его импортирования. Инструкция import — самый распространённый способ вызвать механизм импорта, но не единственный. Для этого также можно использовать, например, функцию importlib.import_module() или встроенную функцию __import__().
Инструкция import объединяет две операции: она ищет модуль с указанным именем, а затем связывает результат поиска с именем в локальной области видимости. Операция поиска в инструкции import определяется как вызов функции __import__() с соответствующими аргументами. Возвращаемое значение __import__() используется для выполнения операции связывания имени в инструкции import. Точные сведения об этой операции связывания имени см. в описании инструкции import.
Прямой вызов __import__() выполняет только поиск модуля и, если он найден, создание объекта модуля. Могут возникать некоторые побочные эффекты, например импорт родительских пакетов и обновление различных кэшей (включая sys.modules), но операцию связывания имени выполняет только инструкция import.
Когда выполняется инструкция import, вызывается стандартная встроенная функция __import__(). Другие механизмы вызова системы импорта (например, importlib.import_module()) могут обойти __import__() и реализовать семантику импорта собственными средствами.
Когда модуль импортируется впервые, Python ищет его и, если находит, создаёт объект модуля [1] и инициализирует его. Если модуль с указанным именем найти не удаётся, возбуждается исключение ModuleNotFoundError. При вызове механизма импорта Python использует различные стратегии поиска модуля с указанным именем. Эти стратегии можно изменять и расширять с помощью различных обработчиков импорта, описанных в разделах ниже.
Изменено в версии 3.3: Система импорта была обновлена и теперь полностью реализует вторую фазу PEP 302. Неявного механизма импорта больше нет — вся система импорта доступна через sys.meta_path. Кроме того, реализована встроенная поддержка пакетов пространства имён (см. PEP 420).
5.1. importlib¶
Модуль importlib предоставляет богатый API для взаимодействия с системой импорта. Например, importlib.import_module() — рекомендуемый API для вызова механизма импорта, более простой, чем у встроенной функции __import__(). Дополнительные сведения см. в документации библиотеки importlib.
5.2. Пакеты¶
В Python есть только один тип объектов модулей, и все модули принадлежат к этому типу независимо от того, реализованы ли они на Python, на C или на чём-то ещё. Чтобы помочь организовать модули и обеспечить иерархию имён, в Python есть понятие пакетов.
Пакеты можно представлять как каталоги в файловой системе, а модули — как файлы внутри каталогов, но не стоит понимать эту аналогию слишком буквально: пакеты и модули не обязаны происходить из файловой системы. В этой документации мы будем использовать эту удобную аналогию с каталогами и файлами. Как и каталоги файловой системы, пакеты организованы иерархически, и пакеты сами могут содержать подпакеты, а также обычные модули.
Важно помнить, что все пакеты являются модулями, но не все модули являются пакетами. Иначе говоря, пакеты — это просто особый вид модулей. А именно, любой модуль, содержащий атрибут __path__, считается пакетом.
У всех модулей есть имя. Имена подпакетов отделяются от имени родительского пакета точкой, подобно стандартному синтаксису доступа к атрибутам в Python. Так, у вас может быть пакет email, у которого, в свою очередь, есть подпакет email.mime, а в этом подпакете — модуль email.mime.text.
5.2.1. Обычные пакеты¶
Python определяет два типа пакетов: обычные пакеты и пакеты пространства имён. Обычные пакеты — это традиционные пакеты, какими они были в Python 3.2 и более ранних версиях. Обычный пакет, как правило, реализуется в виде каталога, содержащего файл __init__.py. При импорте обычного пакета этот файл __init__.py неявно выполняется, а определённые в нём объекты связываются с именами в пространстве имён пакета. Файл __init__.py может содержать тот же код Python, что и любой другой модуль, а при импорте Python добавит к модулю некоторые дополнительные атрибуты.
Например, следующая структура файловой системы определяет пакет верхнего уровня parent с тремя подпакетами:
parent/
__init__.py
one/
__init__.py
two/
__init__.py
three/
__init__.py
Импорт parent.one неявно выполнит parent/__init__.py и parent/one/__init__.py. Последующие импорты parent.two или parent.three выполнят parent/two/__init__.py и parent/three/__init__.py соответственно.
Подкаталог внутри обычного пакета, не содержащий файла __init__.py, рассматривается как неявный пакет пространства имён («подпакет пространства имён») с корнем в этом родительском пакете. Лежащую в основе спецификацию см. в PEP 420.
5.2.2. Пакеты пространства имён¶
Пакет пространства имён составлен из различных частей, каждая из которых вносит в родительский пакет один подпакет. Части могут находиться в разных местах файловой системы. Их можно также найти в zip-файлах, в сети или где-либо ещё, где Python выполняет поиск при импорте. Пакеты пространства имён могут как напрямую соответствовать объектам файловой системы, так и не соответствовать им. Они могут быть виртуальными модулями, не имеющими конкретного представления.
Пакеты пространства имён не используют для своего атрибута __path__ обычный список. Вместо этого они используют собственный итерируемый тип, который при следующей попытке импорта внутри этого пакета автоматически выполняет новый поиск частей пакета, если путь их родительского пакета (или sys.path для пакета верхнего уровня) изменился.
У пакетов пространства имён нет файла parent/__init__.py. Более того, при поиске для импорта может найтись несколько каталогов parent, каждый из которых предоставлен отдельной частью. Поэтому parent/one может физически находиться не рядом с parent/two. В этом случае Python создаёт пакет пространства имён для пакета верхнего уровня parent всякий раз, когда импортируется он сам или один из его подпакетов.
Пакеты пространства имён могут также быть вложены в обычный пакет. Когда система импорта просматривает __path__ обычного пакета и встречает подкаталог, не содержащий файла __init__.py, этот подкаталог становится частью, вносящей вклад в подпакет пространства имён охватывающего обычного пакета.
См. также PEP 420 — спецификацию пакетов пространства имён.
5.3. Поиск¶
Чтобы начать поиск, Python нужно полное квалифицированное имя импортируемого модуля (или пакета, но для целей этого обсуждения разница несущественна). Это имя может поступать из различных аргументов инструкции import или из параметров функций importlib.import_module() и __import__().
Это имя будет использоваться на различных этапах поиска при импорте и может быть путём к подмодулю в точечной нотации, например foo.bar.baz. В этом случае Python сначала пытается импортировать foo, затем foo.bar и, наконец, foo.bar.baz. Если какой-либо из промежуточных импортов завершается неудачей, возбуждается исключение ModuleNotFoundError.
5.3.1. Кэш модулей¶
Первое место, которое проверяется при поиске для импорта, — sys.modules. Это отображение служит кэшем всех ранее импортированных модулей, включая промежуточные пути. Так, если ранее был импортирован foo.bar.baz, то sys.modules будет содержать записи для foo, foo.bar и foo.bar.baz. Значением каждого ключа служит соответствующий объект модуля.
При импорте имя модуля ищется в sys.modules, и если оно там есть, то связанное с ним значение и есть модуль, удовлетворяющий импорту, а процесс на этом завершается. Однако если значение равно None, возбуждается исключение ModuleNotFoundError. Если имя модуля отсутствует, Python продолжит поиск этого модуля.
sys.modules доступен для записи. Удаление ключа не обязательно уничтожит связанный с ним модуль (поскольку другие модули могут хранить на него ссылки), но сделает недействительной запись кэша для этого модуля, и при следующем импорте Python будет искать его заново. Ключу также можно присвоить None, чтобы следующий импорт модуля завершился исключением ModuleNotFoundError.
Но будьте осторожны: если вы сохраните ссылку на объект модуля, сделаете недействительной его запись в sys.modules, а затем заново импортируете этот модуль, то два объекта модуля не будут одним и тем же объектом. Напротив, importlib.reload() использует тот же самый объект модуля и просто заново инициализирует его содержимое, повторно выполняя код модуля.
5.3.2. Поисковики и загрузчики¶
Если модуль с заданным именем не найден в sys.modules, вызывается протокол импорта Python, чтобы найти и загрузить этот модуль. Протокол состоит из двух концептуальных объектов — поисковиков и загрузчиков. Задача поисковика — определить, может ли он найти модуль с заданным именем с помощью известной ему стратегии. Объекты, реализующие оба этих интерфейса, называются импортёрами: они возвращают сами себя, когда обнаруживают, что могут загрузить запрошенный модуль.
В Python есть несколько поисковиков и импортёров по умолчанию. Первый умеет находить встроенные модули, второй — замороженные. Третий поисковик по умолчанию ищет модули по пути импорта. Путь импорта — это список местоположений, которые могут указывать на пути файловой системы или zip-файлы. Его можно расширить так, чтобы поиск охватывал любой ресурс, местоположение которого можно определить, например ресурсы, заданные URL-адресами.
Механизм импорта можно дополнять: чтобы расширить диапазон и область поиска модулей, достаточно добавить новые поисковики.
Поисковики на самом деле не загружают модули. Если они могут найти модуль с заданным именем, то возвращают спецификацию модуля — инкапсулированную информацию о модуле, связанную с его импортом, которую затем использует механизм импорта при загрузке модуля.
В следующих разделах подробнее описан протокол поисковиков и загрузчиков, включая то, как создавать и регистрировать новые, чтобы расширить механизм импорта.
Изменено в версии 3.4: В предыдущих версиях Python поисковики возвращали загрузчики напрямую, тогда как теперь они возвращают спецификации модулей, которые содержат загрузчики. Загрузчики по-прежнему используются при импорте, но у них стало меньше обязанностей.
5.3.3. Обработчики импорта¶
Механизм импорта спроектирован так, чтобы его можно было дополнять; главным способом для этого служат обработчики импорта. Существует два типа обработчиков импорта: метаобработчики и обработчики пути импорта.
Метаобработчики вызываются в начале обработки импорта, до любой другой обработки, кроме поиска в кэше sys.modules. Это позволяет метаобработчикам переопределять обработку sys.path, замороженные модули и даже встроенные модули. Метаобработчики регистрируются добавлением новых объектов-поисковиков в sys.meta_path, как описано ниже.
Обработчики пути импорта вызываются как часть обработки sys.path (или package.__path__) в тот момент, когда встречается связанный с ними элемент пути. Обработчики пути импорта регистрируются добавлением новых вызываемых объектов в sys.path_hooks, как описано ниже.
5.3.4. Мета-путь¶
Если модуль с заданным именем не найден в sys.modules, Python затем просматривает sys.meta_path, содержащий список объектов поисковиков мета-пути. Эти поисковики опрашиваются по порядку, чтобы выяснить, умеют ли они обрабатывать модуль с заданным именем. Поисковики мета-пути должны реализовывать метод find_spec(), принимающий три аргумента: имя, путь импорта и (необязательно) целевой модуль. Поисковик мета-пути может использовать любую стратегию, чтобы определить, может ли он обработать модуль с заданным именем.
Если поисковик мета-пути умеет обрабатывать модуль с заданным именем, он возвращает объект спецификации. Если он не может обработать модуль, он возвращает None. Если обработка sys.meta_path доходит до конца списка и спецификация не возвращена, возбуждается исключение ModuleNotFoundError. Любые другие возбуждённые исключения просто передаются выше, прерывая процесс импорта.
Метод find_spec() поисковиков мета-пути вызывается с двумя или тремя аргументами. Первый — полное квалифицированное имя импортируемого модуля, например foo.bar.baz. Второй аргумент — элементы пути, используемые для поиска модуля. Для модулей верхнего уровня второй аргумент равен None, а для подмодулей или подпакетов — значению атрибута __path__ родительского пакета. Если нужный атрибут __path__ недоступен, возбуждается исключение ModuleNotFoundError. Третий аргумент — существующий объект модуля, который позднее станет целью загрузки. Система импорта передаёт целевой модуль только при перезагрузке.
Мета-путь может обходиться несколько раз для одного запроса на импорт. Например, если предположить, что ни один из задействованных модулей ещё не был кэширован, то импорт foo.bar.baz сначала выполнит импорт верхнего уровня, вызывая mpf.find_spec("foo", None, None) у каждого поисковика мета-пути (mpf). После того как foo будет импортирован, foo.bar будет импортирован вторым обходом мета-пути с вызовом mpf.find_spec("foo.bar", foo.__path__, None). Когда foo.bar будет импортирован, последний обход вызовет mpf.find_spec("foo.bar.baz", foo.bar.__path__, None).
Некоторые поисковики мета-пути поддерживают только импорт верхнего уровня. Эти импортёры всегда возвращают None, если в качестве второго аргумента передано что-либо, кроме None.
В sys.meta_path по умолчанию в Python есть три поисковика мета-пути: один умеет импортировать встроенные модули, другой — замороженные, а третий — модули из пути импорта (то есть поисковик на основе пути).
Изменено в версии 3.4: Метод find_spec() поисковиков мета-пути заменил find_module(), который теперь объявлен устаревшим. Он продолжит работать без изменений, но механизм импорта будет пробовать его, только если поисковик не реализует find_spec().
Изменено в версии 3.10: Использование find_module() системой импорта теперь возбуждает ImportWarning.
Изменено в версии 3.12: Метод find_module() удалён. Вместо него используйте find_spec().
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
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.The module will exist in
sys.modulesbefore the loader executes the module code. This is crucial because the module code may (directly or indirectly) import itself; adding it tosys.modulesbeforehand prevents unbounded recursion in the worst case and multiple loading in the best.If loading fails, the failing module – and only the failing module – gets removed from
sys.modules. Any module already in thesys.modulescache, and any module that was successfully loaded as a side-effect, must remain in the cache. This contrasts with reloading where even the failing module is left insys.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.
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].
Изменено в версии 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.
Изменено в версии 3.15: The load_module method is no longer used.
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. Any value
returned from exec_module() is ignored.
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__).If the loader cannot execute the module, it should raise an
ImportError, although any other exception raised duringexec_module()will be propagated.
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.
Module loaders may opt in to creating the module object during loading
by implementing a create_module() method.
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. If the method returns None, the
import machinery will create the new module itself.
Добавлено в версии 3.4: The create_module() method of loaders.
Изменено в версии 3.4: The importlib.abc.Loader.load_module method was replaced by
exec_module() and the import
machinery assumed all the boilerplate responsibilities of loading.
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(). However, load_module() has been
deprecated and loaders should implement exec_module() instead.
The load_module() method must implement all the boilerplate loading
functionality described above in addition to executing the 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. (Otherwise,importlib.reload()will not work correctly.) If the named module does not exist insys.modules, the loader must create a new module object and add it tosys.modules.The module must exist in
sys.modulesbefore the loader executes the module code, to prevent unbounded recursion or multiple loading.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.
Изменено в версии 3.5: A DeprecationWarning is raised when exec_module() is defined but
create_module() is not.
Изменено в версии 3.6: An ImportError is raised when exec_module() is defined but
create_module() is not.
Изменено в версии 3.10: Use of load_module() will raise 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.
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. Let’s say you have the following directory structure:
spam/
__init__.py
foo.py
and spam/__init__.py has the following line in it:
from .foo import Foo
then executing the following puts name bindings for foo and Foo in the
spam module:
>>> 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. 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.
5.4.3. Module specs¶
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 module.__spec__. Setting
__spec__ appropriately applies equally to
modules initialized during interpreter startup.
The one exception is __main__, where __spec__ is
set to None in some cases.
See ModuleSpec for details on the contents of
the module spec.
Добавлено в версии 3.4.
5.4.4. __path__ attributes on modules¶
The __path__ attribute should be a (possibly empty)
sequence of strings enumerating the locations where the package’s
submodules will be found. By definition, if a module has a __path__
attribute, it is a package.
A package’s __path__ attribute is used during imports of its
subpackages.
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.
However, __path__ is typically much more constrained than
sys.path.
The same rules used for sys.path also apply to a package’s
__path__. sys.path_hooks (described below) are
consulted when traversing a package’s __path__.
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. 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.
5.4.5. 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.
If the module has a spec (__spec__), the import machinery will try
to generate a repr from it. If that fails or there is no spec, the import
system will craft a default repr using whatever information is available
on the module. 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.
Here are the exact rules used:
If the module has a
__spec__attribute, the information in the spec is used to generate the repr. The «name», «loader», «origin», and «has_location» attributes are consulted.If the module has a
__file__attribute, this is used as part of the module’s 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.Otherwise, just use the module’s
__name__in the repr.
Изменено в версии 3.12: Use of module_repr(), having been deprecated since Python 3.4, was
removed in Python 3.12 and is no longer called during the resolution of a
module’s repr.
5.4.6. 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. By default, Python does this
by storing the source’s last-modified timestamp and size in the cache file when
writing it. 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. There are two variants of hash-based
.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. If a checked hash-based cache
file is found to be invalid, Python regenerates it and writes a new checked
hash-based cache file. For unchecked hash-based .pyc files, Python simply
assumes the cache file is valid if it exists. Hash-based .pyc files
validation behavior may be overridden with the --check-hash-based-pycs
flag.
Изменено в версии 3.7: Added hash-based .pyc files. Previously, Python only supported
timestamp-based invalidation of bytecode caches.
5.5. The Path Based Finder¶
As mentioned previously, Python comes with several default meta path finders.
One of these, called the path based finder
(PathFinder), searches an import path,
which contains a list of path entries. 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). 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.
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.
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. 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.
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.
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.
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. 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.
Three variables are used by the path based finder, sys.path,
sys.path_hooks and sys.path_importer_cache. The __path__
attributes on package objects are also used. 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. 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. Only strings should be present on
sys.path; all other data types are ignored.
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. 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. If the path argument is
None, this indicates a top level import and sys.path is used.
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. 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. 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).
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.
If the path entry is not present in the cache, the path based finder iterates
over every callable in 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. An ImportError is used by the path based finder to
signal that the hook cannot find a path entry finder
for that path entry. 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.
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.
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.
The current working directory – denoted by an empty string – is handled
slightly differently from other entries on sys.path. First, if the
current working directory cannot be determined or is found not to exist, no
value is stored in 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.
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() 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).
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.
Изменено в версии 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.
Older path entry finders may implement one of these two deprecated methods
instead of 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_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.
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.
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).
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. 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().
Изменено в версии 3.10: Calls to find_module() and
find_loader() by the import
system will raise ImportWarning.
Изменено в версии 3.12: find_module() and find_loader() have been removed.
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.
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.
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. 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:
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 XXX.YYY.ZZZ
should expose XXX.YYY.ZZZ as a usable expression, but .moduleY is
not a valid expression.
5.8. Special considerations for __main__¶
The __main__ module is a special case relative to Python’s import
system. As noted elsewhere, the __main__ module
is directly initialized at interpreter startup, much like sys and
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.
5.8.1. __main__.__spec__¶
Depending on how __main__ is initialized, __main__.__spec__
gets set appropriately or to None.
When Python is started with the -m option, __spec__ is set
to the module spec of the corresponding module or package. __spec__ is
also populated when the __main__ module is loaded as part of executing a
directory, zipfile or other sys.path entry.
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:
interactive prompt
-coptionrunning from 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. Use the -m switch if valid module metadata is desired
in __main__.
Note also that even when __main__ corresponds with an importable module
and __main__.__spec__ is set accordingly, they’re still considered
distinct modules. 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.
5.9. References¶
The import machinery has evolved considerably since Python’s early days. 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.
PEP 420 introduced namespace packages for
Python 3.3. PEP 420 also introduced the find_loader() protocol as an
alternative to find_module().
PEP 366 describes the addition of the __package__ attribute for
explicit relative imports in main modules.
PEP 328 introduced absolute and explicit relative imports and initially
proposed __name__ for semantics PEP 366 would eventually specify for
__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.
Примечания