import.md
1> **Источник:** https://python-all.ru/3.12/reference/import.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 5. Система импорта89Код Python в одном [модуле](https://python-all.ru/3.12/glossary.html#term-module) получает доступ к коду в другом модуле путем [импортирования](https://python-all.ru/3.12/glossary.html#term-importing) его. Оператор [`import`](https://python-all.ru/3.12/reference/simple_stmts.html#import) является наиболее распространенным способом вызова механизма импорта, но не единственным. Такие функции, как [`importlib.import_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.import_module) и встроенная [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__), также могут использоваться для вызова механизма импорта.1011Оператор [`import`](https://python-all.ru/3.12/reference/simple_stmts.html#import) объединяет две операции: он ищет указанный модуль, а затем привязывает результат этого поиска к имени в локальной области видимости. Операция поиска оператора `import` определяется как вызов функции [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__) с соответствующими аргументами. Возвращаемое значение [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__) используется для выполнения операции привязки имени оператора `import`. Подробности операции привязки имени приведены в описании оператора `import`.1213Прямой вызов [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__) выполняет только поиск модуля и, если он найден, операцию создания модуля. Хотя могут возникать некоторые побочные эффекты, такие как импорт родительских пакетов и обновление различных кешей (включая [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules)), только оператор [`import`](https://python-all.ru/3.12/reference/simple_stmts.html#import) выполняет операцию привязки имени.1415При выполнении оператора [`import`](https://python-all.ru/3.12/reference/simple_stmts.html#import) вызывается стандартная встроенная функция [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__). Другие механизмы вызова системы импорта (например, [`importlib.import_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.import_module)) могут обходить [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__) и использовать собственные решения для реализации семантики импорта.1617При первом импорте модуля Python ищет этот модуль и, если он найден, создает объект модуля [\[1\]](https://python-all.ru/3.12/reference/import.html#fnmo), инициализируя его. Если указанный модуль не найден, возбуждается исключение [`ModuleNotFoundError`](https://python-all.ru/3.12/library/exceptions.html#ModuleNotFoundError). Python реализует различные стратегии поиска указанного модуля при вызове механизма импорта. Эти стратегии можно изменять и расширять с помощью различных хуков, описанных в следующих разделах.1819Изменено в версии 3.3: Система импорта была обновлена для полной реализации второй фазы [**PEP 302**](https://python-all.ru/3.12/reference/import.html). Больше не существует неявного механизма импорта – вся система импорта доступна через [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path). Кроме того, добавлена поддержка нативных пространств имен пакетов (см. [**PEP 420**](https://python-all.ru/3.12/reference/import.html)).2021## 5.1. [`importlib`](https://python-all.ru/3.12/library/importlib.html#module-importlib)2223Модуль [`importlib`](https://python-all.ru/3.12/library/importlib.html#module-importlib) предоставляет богатый API для взаимодействия с системой импорта. Например, [`importlib.import_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.import_module) предоставляет рекомендуемый, более простой API, чем встроенный [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__), для вызова механизма импорта. За дополнительными сведениями обращайтесь к документации библиотеки [`importlib`](https://python-all.ru/3.12/library/importlib.html#module-importlib).2425## 5.2. Пакеты2627Python 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. To help organize modules and provide a naming hierarchy, Python has a concept of [packages](https://python-all.ru/3.12/glossary.html#term-package).2829Можно представлять пакеты как каталоги в файловой системе, а модули – как файлы в этих каталогах, но не стоит воспринимать эту аналогию слишком буквально, поскольку пакеты и модули не обязательно происходят из файловой системы. В целях данной документации мы будем использовать эту удобную аналогию каталогов и файлов. Как и каталоги файловой системы, пакеты организованы иерархически, и пакеты могут содержать вложенные пакеты, а также обычные модули.3031Важно помнить, что все пакеты являются модулями, но не все модули являются пакетами. Или, иными словами, пакеты – это просто особый вид модуля. В частности, любой модуль, содержащий атрибут `__path__`, считается пакетом.3233Все модули имеют имя. Имена вложенных пакетов отделяются от имени родительского пакета точкой, как в стандартном синтаксисе доступа к атрибутам Python. Таким образом, может существовать пакет [`email`](https://python-all.ru/3.12/library/email.html#module-email), который содержит вложенный пакет [`email.mime`](https://python-all.ru/3.12/library/email.mime.html#module-email.mime), а внутри этого вложенного пакета – модуль [`email.mime.text`](https://python-all.ru/3.12/library/email.mime.html#module-email.mime.text).3435### 5.2.1. Обычные пакеты3637Python defines two types of packages, [regular packages](https://python-all.ru/3.12/glossary.html#term-regular-package) and [namespace packages](https://python-all.ru/3.12/glossary.html#term-namespace-package). Regular packages are traditional packages as they existed in Python 3.2 and earlier. A regular package is typically implemented as a directory containing an `__init__.py` file. 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. 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.3839Например, следующая структура файловой системы определяет пакет верхнего уровня `parent` с тремя вложенными пакетами:4041```python42parent/43 __init__.py44 one/45 __init__.py46 two/47 __init__.py48 three/49 __init__.py50```5152Импорт `parent.one` неявно выполнит `parent/__init__.py` и `parent/one/__init__.py`. Последующие импорты `parent.two` или `parent.three` выполнят `parent/two/__init__.py` и `parent/three/__init__.py` соответственно.5354### 5.2.2. Пакеты пространств имен5556A namespace package is a composite of various [portions](https://python-all.ru/3.12/glossary.html#term-portion), 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. Namespace packages may or may not correspond directly to objects on the file system; they may be virtual modules that have no concrete representation.5758Пакеты пространств имен не используют обычный список для своего атрибута `__path__`. Вместо этого они используют пользовательский итерируемый тип, который автоматически выполняет новый поиск частей пакета при следующей попытке импорта в рамках этого пакета, если путь родительского пакета (или [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path) для пакета верхнего уровня) изменяется.5960В пакетах пространств имен нет файла `parent/__init__.py`. Фактически, при поиске импорта может быть найдено несколько каталогов `parent`, каждый из которых предоставляется разной частью. Таким образом, `parent/one` может физически не находиться рядом с `parent/two`. В этом случае Python создаст пакет пространства имен для пакета верхнего уровня `parent` всякий раз, когда импортируется сам этот пакет или любой из его вложенных пакетов.6162See also [**PEP 420**](https://python-all.ru/3.12/reference/import.html) for the namespace package specification.6364## 5.3. Поиск6566To begin the search, Python needs the [fully qualified](https://python-all.ru/3.12/glossary.html#term-qualified-name) name of the module (or package, but for the purposes of this discussion, the difference is immaterial) being imported. This name may come from various arguments to the [`import`](https://python-all.ru/3.12/reference/simple_stmts.html#import) statement, or from the parameters to the [`importlib.import_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.import_module) or [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__) functions.6768Это имя будет использоваться на различных этапах поиска импорта и может быть точечным путём к подмодулю, например `foo.bar.baz`. В этом случае Python сначала пытается импортировать `foo`, затем `foo.bar` и, наконец, `foo.bar.baz`. Если какой-либо из промежуточных импортов завершается неудачей, возбуждается [`ModuleNotFoundError`](https://python-all.ru/3.12/library/exceptions.html#ModuleNotFoundError).6970### 5.3.1. Кеш модулей7172Первое место, проверяемое при поиске импорта, – это [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules). Это отображение служит кешем всех ранее импортированных модулей, включая промежуточные пути. Таким образом, если `foo.bar.baz` был ранее импортирован, [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules) будет содержать записи для `foo`, `foo.bar` и `foo.bar.baz`. Каждый ключ будет иметь в качестве значения соответствующий объект модуля.7374Во время импорта имя модуля ищется в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules), и если оно присутствует, связанное значение является модулем, удовлетворяющим импорт, и процесс завершается. Однако если значением является `None`, то возбуждается [`ModuleNotFoundError`](https://python-all.ru/3.12/library/exceptions.html#ModuleNotFoundError). Если имя модуля отсутствует, Python продолжает поиск модуля.7576[`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules) доступен для записи. Удаление ключа может не уничтожить связанный модуль (поскольку другие модули могут хранить на него ссылки), но это сделает недействительной запись кеша для указанного модуля, что заставит Python выполнить новый поиск этого модуля при следующем импорте. Ключ также можно присвоить `None`, что приведет к тому, что следующий импорт модуля завершится [`ModuleNotFoundError`](https://python-all.ru/3.12/library/exceptions.html#ModuleNotFoundError).7778Однако будьте осторожны: если вы сохраните ссылку на объект модуля, сделаете недействительной его запись в кеше [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules), а затем повторно импортируете указанный модуль, два объекта модуля *не* будут одинаковыми. В отличие от этого, [`importlib.reload()`](https://python-all.ru/3.12/library/importlib.html#importlib.reload) будет повторно использовать *тот же* объект модуля и просто повторно инициализирует содержимое модуля, выполнив его код заново.7980### 5.3.2. Искатели и загрузчики8182Если именованный модуль не найден в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules), то вызывается протокол импорта Python для поиска и загрузки модуля. Этот протокол состоит из двух концептуальных объектов: [искателей](https://python-all.ru/3.12/glossary.html#term-finder) и [загрузчиков](https://python-all.ru/3.12/glossary.html#term-loader). Задача искателя – определить, может ли он найти именованный модуль, используя любую известную ему стратегию. Объекты, реализующие оба этих интерфейса, называются [импортерами](https://python-all.ru/3.12/glossary.html#term-importer) – они возвращают самих себя, когда обнаруживают, что могут загрузить запрошенный модуль.8384Python includes a number of default finders and importers. 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](https://python-all.ru/3.12/glossary.html#term-import-path) for modules. The [import path](https://python-all.ru/3.12/glossary.html#term-import-path) is a list of locations that may name file system paths or zip files. It can also be extended to search for any locatable resource, such as those identified by URLs.8586Механизм импорта является расширяемым, поэтому можно добавлять новые искатели для расширения диапазона и области поиска модулей.8788Искатели на самом деле не загружают модули. Если они могут найти именованный модуль, они возвращают *спецификацию модуля* – инкапсуляцию информации, связанной с импортом модуля, которую затем использует механизм импорта при загрузке модуля.8990В следующих разделах протокол для искателей и загрузчиков описывается более подробно, включая то, как можно создавать и регистрировать новые для расширения механизма импорта.9192Изменено в версии 3.4: В предыдущих версиях Python искатели возвращали [загрузчики](https://python-all.ru/3.12/glossary.html#term-loader) напрямую, тогда как теперь они возвращают спецификации модулей, которые *содержат* загрузчики. Загрузчики по-прежнему используются при импорте, но имеют меньше обязанностей.9394### 5.3.3. Хуки импорта9596Механизм импорта разработан как расширяемый; основным механизмом для этого являются *хуки импорта*. Существует два типа хуков импорта: *мета-хуки* и *хуки пути импорта*.9798Мета-хуки вызываются в начале обработки импорта, до того, как произойдет любая другая обработка импорта, кроме поиска в кеше [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules). Это позволяет мета-хукам переопределять обработку [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path), замороженных модулей или даже встроенных модулей. Мета-хуки регистрируются путем добавления новых объектов искателей в [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path), как описано ниже.99100Хуки пути импорта вызываются как часть обработки [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path) (или `package.__path__`) в тот момент, когда встречается связанный с ними элемент пути. Хуки пути импорта регистрируются путем добавления новых вызываемых объектов в [`sys.path_hooks`](https://python-all.ru/3.12/library/sys.html#sys.path_hooks), как описано ниже.101102### 5.3.4. Мета-путь103104Когда именованный модуль не найден в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules), Python затем ищет в [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path), который содержит список объектов искателей мета-пути. Эти искатели опрашиваются по порядку, чтобы выяснить, знают ли они, как обрабатывать именованный модуль. Искатели мета-пути должны реализовывать метод с именем [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec), который принимает три аргумента: имя, путь импорта и (опционально) целевой модуль. Искатель мета-пути может использовать любую стратегию по своему усмотрению, чтобы определить, может ли он обработать именованный модуль или нет.105106Если искатель мета-пути знает, как обрабатывать именованный модуль, он возвращает объект спецификации. Если он не может обработать именованный модуль, он возвращает `None`. Если обработка [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path) достигает конца своего списка, не вернув спецификацию, то возбуждается [`ModuleNotFoundError`](https://python-all.ru/3.12/library/exceptions.html#ModuleNotFoundError). Любые другие возникшие исключения просто распространяются вверх, прерывая процесс импорта.107108Метод [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec) искателей мета-пути вызывается с двумя или тремя аргументами. Первый – это полное имя импортируемого модуля, например `foo.bar.baz`. Второй аргумент – это записи пути, используемые для поиска модуля. Для модулей верхнего уровня вторым аргументом является `None`, но для подмодулей или подпакетов вторым аргументом является значение атрибута `__path__` родительского пакета. Если соответствующий атрибут `__path__` недоступен, возбуждается [`ModuleNotFoundError`](https://python-all.ru/3.12/library/exceptions.html#ModuleNotFoundError). Третий аргумент – это существующий объект модуля, который будет целью загрузки позже. Система импорта передает целевой модуль только во время перезагрузки.109110Мета-путь может обходиться несколько раз для одного запроса импорта. Например, предполагая, что ни один из задействованных модулей еще не был кеширован, импорт `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)`.111112Некоторые искатели мета-пути поддерживают только импорт верхнего уровня. Эти импортеры всегда будут возвращать `None`, если в качестве второго аргумента передано что-либо, кроме `None`.113114[`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path) по умолчанию Python имеет три искателя мета-пути: один умеет импортировать встроенные модули, один – замороженные модули и один – модули из [пути импорта](https://python-all.ru/3.12/glossary.html#term-import-path) (т.е. [искатель на основе пути](https://python-all.ru/3.12/glossary.html#term-path-based-finder)).115116Изменено в версии 3.4: Метод [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec) искателей мета-пути заменил `find_module()`, который теперь устарел. Хотя он продолжит работать без изменений, механизм импорта будет использовать его только в том случае, если искатель не реализует [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec).117118Изменено в версии 3.10: Использование `find_module()` системой импорта теперь вызывает [`ImportWarning`](https://python-all.ru/3.12/library/exceptions.html#ImportWarning).119120Изменено в версии 3.12: `find_module()` удалён. Вместо него используйте [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec).121122## 5.4. Загрузка123124Если (и когда) спецификация модуля найдена, механизм импорта использует её (и содержащийся в ней загрузчик) при загрузке модуля. Ниже приведено приблизительное описание того, что происходит во время части импорта, связанной с загрузкой:125126```python127module = None128if spec.loader is not None and hasattr(spec.loader, 'create_module'):129 # Предполагается, что 'exec_module' также будет определён в загрузчике.130 module = spec.loader.create_module(spec)131if module is None:132 module = ModuleType(spec.name)133# Здесь задаются атрибуты модуля, связанные с импортом:134_init_module_attrs(spec, module)135136if spec.loader is None:137 # не поддерживается138 raise ImportError139if spec.origin is None and spec.submodule_search_locations is not None:140 # пакет пространства имён141 sys.modules[spec.name] = module142elif not hasattr(spec.loader, 'exec_module'):143 module = spec.loader.load_module(spec.name)144else:145 sys.modules[spec.name] = module146 try:147 spec.loader.exec_module(module)148 except BaseException:149 try:150 del sys.modules[spec.name]151 except KeyError:152 pass153 raise154return sys.modules[spec.name]155```156157Обратите внимание на следующие детали:158159- Если в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules) уже существует объект модуля с указанным именем, импорт уже вернёт его.160- Модуль будет существовать в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules) до того, как загрузчик выполнит код модуля. Это крайне важно, потому что код модуля может (прямо или косвенно) импортировать сам себя; его добавление в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules) заранее предотвращает неограниченную рекурсию в худшем случае и множественную загрузку в лучшем.161- Если загрузка завершается ошибкой, модуль, вызвавший ошибку (и только он), удаляется из [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules). Любой модуль, уже находящийся в кеше [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules), а также любой модуль, который был успешно загружен как побочный эффект, должен оставаться в кеше. Это отличается от перезагрузки, где даже неудачно загруженный модуль остаётся в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules).162- После создания модуля, но до его выполнения, механизм импорта устанавливает атрибуты модуля, связанные с импортом («\_init\_module\_attrs» в примере псевдокода выше), как описано в [следующем разделе](https://python-all.ru/3.12/reference/datamodel.html#import-mod-attrs).163- Выполнение модуля – ключевой момент загрузки, в ходе которого заполняется пространство имён модуля. Выполнение полностью делегируется загрузчику, который решает, что и как заполнять.164- Модуль, созданный во время загрузки и переданный в exec\_module(), может не совпадать с тем, что возвращается в конце импорта [\[2\]](https://python-all.ru/3.12/reference/import.html#fnlo).165166Изменено в версии 3.4: Система импорта взяла на себя стандартные обязанности загрузчиков. Ранее они выполнялись методом [`importlib.abc.Loader.load_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.load_module).167168### 5.4.1. Загрузчики169170Загрузчики модулей выполняют критическую функцию загрузки: выполнение модуля. Механизм импорта вызывает метод [`importlib.abc.Loader.exec_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.exec_module) с одним аргументом – объектом модуля, который нужно выполнить. Любое значение, возвращённое из [`exec_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.exec_module), игнорируется.171172Загрузчики должны удовлетворять следующим требованиям:173174- Если модуль является модулем Python (в отличие от встроенного модуля или динамически загружаемого расширения), загрузчик должен выполнить код модуля в глобальном пространстве имён модуля (`module.__dict__`).175- Если загрузчик не может выполнить модуль, он должен вызвать исключение [`ImportError`](https://python-all.ru/3.12/library/exceptions.html#ImportError), хотя любое другое исключение, возникшее во время [`exec_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.exec_module), будет распространено.176177Во многих случаях искатель и загрузчик могут быть одним и тем же объектом; в таких случаях метод [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec) просто возвращает спецификацию с загрузчиком, установленным в `self`.178179Загрузчики модулей могут реализовать метод [`create_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.create_module), чтобы принять участие в создании объекта модуля во время загрузки. Он принимает один аргумент – спецификацию модуля – и возвращает новый объект модуля для использования во время загрузки. `create_module()` не нужно устанавливать какие-либо атрибуты объекта модуля. Если метод возвращает `None`, механизм импорта создаст новый модуль самостоятельно.180181Добавлено в версии 3.4: Метод [`create_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.create_module) загрузчиков.182183Изменено в версии 3.4: Метод [`load_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.load_module) был заменён на [`exec_module()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.Loader.exec_module), и механизм импорта взял на себя все стандартные обязанности по загрузке.184185Для совместимости с существующими загрузчиками механизм импорта будет использовать метод `load_module()` загрузчиков, если он существует и загрузчик не реализует также `exec_module()`. Однако `load_module()` устарел, и загрузчики должны реализовать `exec_module()` вместо него.186187Метод `load_module()` должен реализовывать всю описанную выше стандартную функциональность загрузки в дополнение к выполнению модуля. Применяются все те же ограничения с некоторыми дополнительными уточнениями:188189- Если в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules) уже существует объект модуля с указанным именем, загрузчик должен использовать этот существующий модуль. (В противном случае [`importlib.reload()`](https://python-all.ru/3.12/library/importlib.html#importlib.reload) не будет работать корректно.) Если именованный модуль не существует в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules), загрузчик должен создать новый объект модуля и добавить его в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules).190- Модуль *должен* существовать в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules) до того, как загрузчик выполнит код модуля, чтобы предотвратить неограниченную рекурсию или многократную загрузку.191- Если загрузка завершается ошибкой, загрузчик должен удалить любые модули, которые он вставил в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules), но он должен удалить **только** модуль(и), загрузка которого завершилась ошибкой, и только если загрузчик сам явно загрузил этот(и) модуль(и).192193Изменено в версии 3.5: Исключение [`DeprecationWarning`](https://python-all.ru/3.12/library/exceptions.html#DeprecationWarning) возбуждается, когда `exec_module()` определён, а `create_module()` – нет.194195Изменено в версии 3.6: Исключение [`ImportError`](https://python-all.ru/3.12/library/exceptions.html#ImportError) возбуждается, когда `exec_module()` определён, а `create_module()` – нет.196197Изменено в версии 3.10: Использование `load_module()` приведёт к возбуждению [`ImportWarning`](https://python-all.ru/3.12/library/exceptions.html#ImportWarning).198199### 5.4.2. Подмодули200201Когда подмодуль загружается с помощью любого механизма (например, API `importlib`, операторов `import` или `import-from`, или встроенной `__import__()`), в пространстве имён родительского модуля создаётся связывание с объектом подмодуля. Например, если пакет `spam` содержит подмодуль `foo`, то после импорта `spam.foo` у `spam` будет атрибут `foo`, который связан с подмодулем. Допустим, имеется следующая структура каталогов:202203```python204spam/205 __init__.py206 foo.py207```208209и `spam/__init__.py` содержит следующую строку:210211```python212from .foo import Foo213```214215тогда выполнение следующего кода помещает связывания имён для `foo` и `Foo` в модуль `spam`:216217```python218>>> import spam219>>> spam.foo220<module 'spam.foo' from '/tmp/imports/spam/foo.py'>221>>> spam.Foo222<class 'spam.foo.Foo'>223```224225Учитывая привычные правила связывания имён в Python, это может показаться удивительным, но на самом деле это фундаментальная особенность системы импорта. Сохраняется следующий инвариант: если имеются `sys.modules['spam']` и `sys.modules['spam.foo']` (как после импорта выше), то второй должен быть атрибутом `foo` первого.226227### 5.4.3. Спецификации модулей228229Механизм импорта использует различную информацию о каждом модуле во время импорта, особенно перед загрузкой. Большая часть этой информации является общей для всех модулей. Назначение спецификации модуля – инкапсулировать эту связанную с импортом информацию для каждого модуля отдельно.230231Использование спецификации во время импорта позволяет передавать состояние между компонентами системы импорта, например, между искателем, который создаёт спецификацию модуля, и загрузчиком, который её выполняет. Самое главное, это позволяет механизму импорта выполнять стандартные операции загрузки, тогда как без спецификации модуля эта ответственность лежала на загрузчике.232233Спецификация модуля доступна как [`module.__spec__`](https://python-all.ru/3.12/reference/datamodel.html#module.__spec__). Установка `__spec__` соответствующим образом в равной степени применима к [модулям, инициализируемым при запуске интерпретатора](https://python-all.ru/3.12/reference/toplevel_components.html#programs). Исключением является `__main__`, где `__spec__` [в некоторых случаях устанавливается в None](https://python-all.ru/3.12/reference/import.html#main-spec).234235Подробнее о содержимом спецификации модуля см. [`ModuleSpec`](https://python-all.ru/3.12/library/importlib.html#importlib.machinery.ModuleSpec).236237Добавлено в версии 3.4.238239### 5.4.4. Атрибуты \_\_path\_\_ модулей240241Атрибут [`__path__`](https://python-all.ru/3.12/reference/datamodel.html#module.__path__) должен представлять собой (возможно, пустую) [последовательность](https://python-all.ru/3.12/glossary.html#term-sequence) строк, перечисляющих расположения, где будут найдены подмодули пакета. По определению, если у модуля есть атрибут `__path__`, то это [пакет](https://python-all.ru/3.12/glossary.html#term-package).242243Атрибут [`__path__`](https://python-all.ru/3.12/reference/datamodel.html#module.__path__) пакета используется при импорте его подпакетов. В механизме импорта он работает практически так же, как [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path), то есть предоставляет список расположений для поиска модулей во время импорта. Однако `__path__` обычно гораздо более ограничен, чем `sys.path`.244245Те же правила, что применяются к [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path), действуют и для `__path__` пакета. [`sys.path_hooks`](https://python-all.ru/3.12/library/sys.html#sys.path_hooks) (описаны ниже) используются при обходе `__path__` пакета.246247Файл `__init__.py` пакета может устанавливать или изменять атрибут [`__path__`](https://python-all.ru/3.12/reference/datamodel.html#module.__path__) пакета, и именно так обычно реализовывались пространства имён пакетов до [**PEP 420**](https://python-all.ru/3.12/reference/import.html). С принятием [**PEP 420**](https://python-all.ru/3.12/reference/import.html) пространства имён пакетов больше не требуют файлов `__init__.py`, содержащих только код манипуляции `__path__`; механизм импорта автоматически устанавливает `__path__` правильно для пространства имён пакета.248249### 5.4.5. Строковые представления модулей250251По умолчанию все модули имеют пригодное строковое представление, однако в зависимости от установленных выше атрибутов и спецификации модуля можно более явно управлять строковым представлением объектов модулей.252253Если у модуля есть спецификация (`__spec__`), механизм импорта попытается сгенерировать строковое представление на её основе. Если это не удаётся или спецификация отсутствует, система импорта создаст строковое представление по умолчанию, используя любую доступную информацию о модуле. Она попытается использовать `module.__name__`, `module.__file__` и `module.__loader__` в качестве входных данных для строкового представления, с умолчаниями для отсутствующей информации.254255Ниже приведены точные правила:256257- Если у модуля есть атрибут `__spec__`, для генерации строкового представления используется информация из спецификации. Учитываются атрибуты «name», «loader», «origin» и «has\_location».258- Если у модуля есть атрибут `__file__`, он используется как часть строкового представления модуля.259- Если у модуля нет `__file__`, но есть `__loader__`, который не равен `None`, то строковое представление загрузчика используется как часть строкового представления модуля.260- В противном случае в строковом представлении используется просто `__name__` модуля.261262Изменено в версии 3.12: Использование `module_repr()`, устаревшее с Python 3.4, было удалено в Python 3.12 и больше не вызывается при формировании строкового представления модуля.263264### 5.4.6. Инвалидация кэшированного байт-кода265266Прежде чем Python загрузит кэшированный байт-код из файла `.pyc`, он проверяет, актуален ли кэш относительно исходного файла `.py`. По умолчанию Python делает это, сохраняя метку времени последнего изменения и размер исходного файла в кэш-файле при его записи. Во время выполнения система импорта затем проверяет кэш-файл, сверяя сохранённые метаданные в кэш-файле с метаданными исходного файла.267268Python также поддерживает кэш-файлы на основе хеша, в которых вместо метаданных хранится хеш содержимого исходного файла. Существует два варианта таких `.pyc` файлов: проверяемые и непроверяемые. Для проверяемых `.pyc` файлов Python проверяет кэш-файл, хешируя исходный файл и сравнивая полученный хеш с хешем в кэш-файле. Если проверяемый кэш-файл на основе хеша оказывается недействительным, Python пересоздаёт его и записывает новый проверяемый кэш-файл на основе хеша. Для непроверяемых `.pyc` файлов Python просто считает кэш-файл действительным, если он существует. Поведение проверки `.pyc` файлов на основе хеша можно переопределить с помощью флага [`--check-hash-based-pycs`](https://python-all.ru/3.12/using/cmdline.html#cmdoption-check-hash-based-pycs).269270Изменено в версии 3.7: Добавлены `.pyc` файлы на основе хеша. Ранее Python поддерживал только инвалидацию кэшей байт-кода на основе временных меток.271272## 5.5. Искатель на основе путей273274Как упоминалось ранее, Python включает несколько искателей мета-путей по умолчанию. Один из них, называемый [искатель на основе путей](https://python-all.ru/3.12/glossary.html#term-path-based-finder) ([`PathFinder`](https://python-all.ru/3.12/library/importlib.html#importlib.machinery.PathFinder)), ищет в [пути импорта](https://python-all.ru/3.12/glossary.html#term-import-path), который содержит список [записей пути](https://python-all.ru/3.12/glossary.html#term-path-entry). Каждая запись пути указывает расположение для поиска модулей.275276Сам искатель на основе путей не знает, как импортировать что-либо. Вместо этого он обходит отдельные записи пути, связывая каждую из них с искателем записей пути, который знает, как обрабатывать этот конкретный тип пути.277278Набор искателей записей пути по умолчанию реализует всю семантику поиска модулей в файловой системе, обрабатывая специальные типы файлов, такие как исходный код Python (файлы `.py`), байт-код Python (файлы `.pyc`) и разделяемые библиотеки (например, файлы `.so`). Если это поддерживается модулем [`zipimport`](https://python-all.ru/3.12/library/zipimport.html#module-zipimport) из стандартной библиотеки, искатели записей пути по умолчанию также загружают все эти типы файлов (кроме разделяемых библиотек) из zip-файлов.279280Записи пути не обязаны ограничиваться расположениями в файловой системе. Они могут ссылаться на URL, запросы к базе данных или любые другие расположения, которые можно указать в виде строки.281282Искатель на основе путей предоставляет дополнительные перехватчики и протоколы, позволяющие расширять и настраивать типы искомых записей пути. Например, если требуется поддерживать записи пути в виде сетевых URL, можно написать перехватчик, реализующий семантику HTTP для поиска модулей в вебе. Этот перехватчик (вызываемый объект) вернёт [искатель записей пути](https://python-all.ru/3.12/glossary.html#term-path-entry-finder), поддерживающий описанный ниже протокол, который затем будет использован для получения загрузчика модуля из веба.283284Предупреждение: в этом и предыдущем разделах используется термин *finder (искатель)*, различая их с помощью терминов [искатель мета-путей](https://python-all.ru/3.12/glossary.html#term-meta-path-finder) и [искатель записей пути](https://python-all.ru/3.12/glossary.html#term-path-entry-finder). Эти два типа искателей очень похожи, поддерживают схожие протоколы и действуют схожим образом в процессе импорта, однако важно помнить, что между ними есть тонкие различия. В частности, искатели мета-путей работают в начале процесса импорта, начиная с обхода [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path).285286Напротив, искатели записей пути в некотором смысле являются деталью реализации искателя на основе путей, и на самом деле, если бы искатель на основе путей был удалён из [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path), ни одна из семантик искателя записей пути не была бы задействована.287288### 5.5.1. Искатели записей пути289290[Искатель на основе путей](https://python-all.ru/3.12/glossary.html#term-path-based-finder) отвечает за поиск и загрузку модулей и пакетов Python, расположение которых задаётся строковой [записью пути](https://python-all.ru/3.12/glossary.html#term-path-entry). Большинство записей пути указывают на расположения в файловой системе, но не обязаны ограничиваться этим.291292Будучи искателем мета-путей, [искатель на основе путей](https://python-all.ru/3.12/glossary.html#term-path-based-finder) реализует протокол [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec), описанный ранее, однако он также предоставляет дополнительные перехватчики, которые можно использовать для настройки того, как модули находятся и загружаются из [пути импорта](https://python-all.ru/3.12/glossary.html#term-import-path).293294[Искатель на основе путей](https://python-all.ru/3.12/glossary.html#term-path-based-finder) использует три переменные: [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path), [`sys.path_hooks`](https://python-all.ru/3.12/library/sys.html#sys.path_hooks) и [`sys.path_importer_cache`](https://python-all.ru/3.12/library/sys.html#sys.path_importer_cache). Также используются атрибуты `__path__` объектов пакетов. Они предоставляют дополнительные способы настройки механизма импорта.295296[`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path) содержит список строк, предоставляющих расположения для поиска модулей и пакетов. Он инициализируется из переменной окружения [`PYTHONPATH`](https://python-all.ru/3.12/using/cmdline.html#envvar-PYTHONPATH) и различных других умолчаний, зависящих от установки и реализации. Записи в [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path) могут указывать на каталоги в файловой системе, zip-файлы и потенциально другие «расположения» (см. модуль [`site`](https://python-all.ru/3.12/library/site.html#module-site)), которые следует искать для модулей, например URL или запросы к базам данных. В [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path) должны присутствовать только строки; все остальные типы данных игнорируются.297298[Искатель на основе путей](https://python-all.ru/3.12/glossary.html#term-path-based-finder) является [искателем мета-путей](https://python-all.ru/3.12/glossary.html#term-meta-path-finder), поэтому механизм импорта начинает поиск [пути импорта](https://python-all.ru/3.12/glossary.html#term-import-path) вызовом метода [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.machinery.PathFinder.find_spec) искателя на основе путей, как описано ранее. Когда аргумент `path` для [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.machinery.PathFinder.find_spec) задан, это будет список строковых путей для обхода – обычно атрибут `__path__` пакета для импорта внутри этого пакета. Если аргумент `path` равен `None`, это указывает на импорт верхнего уровня, и используется [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path).299300The path based finder iterates over every entry in the search path, and for each of these, looks for an appropriate [path entry finder](https://python-all.ru/3.12/glossary.html#term-path-entry-finder) ([`PathEntryFinder`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.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`](https://python-all.ru/3.12/library/sys.html#sys.path_importer_cache) (despite the name, this cache actually stores finder objects rather than being limited to [importer](https://python-all.ru/3.12/glossary.html#term-importer) objects). In this way, the expensive search for a particular [path entry](https://python-all.ru/3.12/glossary.html#term-path-entry) location’s [path entry finder](https://python-all.ru/3.12/glossary.html#term-path-entry-finder) need only be done once. User code is free to remove cache entries from [`sys.path_importer_cache`](https://python-all.ru/3.12/library/sys.html#sys.path_importer_cache) forcing the path based finder to perform the path entry search again.301302If the path entry is not present in the cache, the path based finder iterates over every callable in [`sys.path_hooks`](https://python-all.ru/3.12/library/sys.html#sys.path_hooks). Each of the [path entry hooks](https://python-all.ru/3.12/glossary.html#term-path-entry-hook) in this list is called with a single argument, the path entry to be searched. This callable may either return a [path entry finder](https://python-all.ru/3.12/glossary.html#term-path-entry-finder) that can handle the path entry, or it may raise [`ImportError`](https://python-all.ru/3.12/library/exceptions.html#ImportError). An [`ImportError`](https://python-all.ru/3.12/library/exceptions.html#ImportError) is used by the path based finder to signal that the hook cannot find a [path entry finder](https://python-all.ru/3.12/glossary.html#term-path-entry-finder) for that [path entry](https://python-all.ru/3.12/glossary.html#term-path-entry). The exception is ignored and [import path](https://python-all.ru/3.12/glossary.html#term-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`](https://python-all.ru/3.12/library/exceptions.html#ImportError).303304If [`sys.path_hooks`](https://python-all.ru/3.12/library/sys.html#sys.path_hooks) iteration ends with no [path entry finder](https://python-all.ru/3.12/glossary.html#term-path-entry-finder) being returned, then the path based finder’s [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.machinery.PathFinder.find_spec) method will store `None` in [`sys.path_importer_cache`](https://python-all.ru/3.12/library/sys.html#sys.path_importer_cache) (to indicate that there is no finder for this path entry) and return `None`, indicating that this [meta path finder](https://python-all.ru/3.12/glossary.html#term-meta-path-finder) could not find the module.305306If a [path entry finder](https://python-all.ru/3.12/glossary.html#term-path-entry-finder) *is* returned by one of the [path entry hook](https://python-all.ru/3.12/glossary.html#term-path-entry-hook) callables on [`sys.path_hooks`](https://python-all.ru/3.12/library/sys.html#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.307308Текущий рабочий каталог – обозначаемый пустой строкой – обрабатывается несколько иначе, чем другие записи в [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path). Во-первых, если текущий рабочий каталог не существует, в [`sys.path_importer_cache`](https://python-all.ru/3.12/library/sys.html#sys.path_importer_cache) не сохраняется никакого значения. Во-вторых, значение текущего рабочего каталога запрашивается заново при каждом поиске модуля. В-третьих, путь, используемый для [`sys.path_importer_cache`](https://python-all.ru/3.12/library/sys.html#sys.path_importer_cache) и возвращаемый [`importlib.machinery.PathFinder.find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.machinery.PathFinder.find_spec), будет фактическим текущим рабочим каталогом, а не пустой строкой.309310### 5.5.2. Протокол искателя записей пути311312Для поддержки импорта модулей и инициализированных пакетов, а также для внесения частей в пространственно-именованные пакеты, искатели записей пути должны реализовывать метод [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.PathEntryFinder.find_spec).313314[`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.PathEntryFinder.find_spec) принимает два аргумента: полное имя импортируемого модуля и (необязательный) целевой модуль. `find_spec()` возвращает полностью заполненную спецификацию для модуля. В этой спецификации всегда будет установлен атрибут «loader» (за одним исключением).315316To indicate to the import machinery that the spec represents a namespace [portion](https://python-all.ru/3.12/glossary.html#term-portion), the path entry finder sets `submodule_search_locations` to a list containing the portion.317318Изменено в версии 3.4: [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.PathEntryFinder.find_spec) заменил `find_loader()` и `find_module()`, оба из которых теперь устарели, но будут использоваться, если `find_spec()` не определён.319320Более старые искатели записей пути могут реализовывать один из двух устаревших методов вместо `find_spec()`. Эти методы по-прежнему учитываются для обратной совместимости. Однако, если на искателе записей пути реализован `find_spec()`, устаревшие методы игнорируются.321322`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](https://python-all.ru/3.12/glossary.html#term-portion).323324Для обратной совместимости с другими реализациями протокола импорта многие искатели записей пути также поддерживают тот же традиционный метод `find_module()`, который поддерживают искатели метапути. Однако методы `find_module()` искателей записей пути никогда не вызываются с аргументом `path` (предполагается, что они записывают соответствующую информацию о пути из первоначального вызова хука пути).325326Метод `find_module()` у искателей записей пути устарел, так как он не позволяет искателю записей пути вносить части в пространственно-именованные пакеты. Если на искателе записей пути существуют и `find_loader()`, и `find_module()`, система импорта всегда будет вызывать `find_loader()` в предпочтение `find_module()`.327328Изменено в версии 3.10: Вызовы `find_module()` и `find_loader()` системой импорта будут возбуждать [`ImportWarning`](https://python-all.ru/3.12/library/exceptions.html#ImportWarning).329330Изменено в версии 3.12: `find_module()` и `find_loader()` были удалены.331332## 5.6. Замена стандартной системы импорта333334Самый надёжный механизм замены всей системы импорта – удалить содержимое по умолчанию из [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path), полностью заменив их пользовательским хуком метапути.335336Если достаточно изменить поведение только инструкций import, не затрагивая другие API, которые обращаются к системе импорта, то может быть достаточно замены встроенной функции [`__import__()`](https://python-all.ru/3.12/library/functions.html#import__). Этот метод также можно применить на уровне модуля, чтобы изменить поведение инструкций import только в этом модуле.337338Чтобы выборочно предотвратить импорт некоторых модулей из хука на раннем этапе метапути (вместо полного отключения стандартной системы импорта), достаточно возбудить [`ModuleNotFoundError`](https://python-all.ru/3.12/library/exceptions.html#ModuleNotFoundError) непосредственно из [`find_spec()`](https://python-all.ru/3.12/library/importlib.html#importlib.abc.MetaPathFinder.find_spec), а не возвращать `None`. Последнее означает, что поиск по метапути должен продолжаться, тогда как возбуждение исключения немедленно его прекращает.339340## 5.7. Относительный импорт в пакетах341342Относительный импорт использует начальные точки. Одна начальная точка означает относительный импорт, начиная с текущего пакета. Две или более начальных точек означают относительный импорт к родительским пакетам текущего пакета, один уровень на каждую точку после первой. Например, при следующей структуре пакета:343344```python345package/346 __init__.py347 subpackage1/348 __init__.py349 moduleX.py350 moduleY.py351 subpackage2/352 __init__.py353 moduleZ.py354 moduleA.py355```356357В любом из `subpackage1/moduleX.py` или `subpackage1/__init__.py` следующие относительные импорты допустимы:358359```python360from .moduleY import spam361from .moduleY import spam as ham362from . import moduleY363from ..subpackage1 import moduleY364from ..subpackage2.moduleZ import eggs365from ..moduleA import foo366```367368Абсолютный импорт может использовать синтаксис `import <>` или `from <> import <>`, но относительный импорт может использовать только вторую форму; причина в том, что:369370```python371import XXX.YYY.ZZZ372```373374должен предоставлять `XXX.YYY.ZZZ` как допустимое выражение, тогда как .moduleY не является допустимым выражением.375376## 5.8. Особые соображения для \_\_main\_\_377378The [`__main__`](https://python-all.ru/3.12/library/__main__.html#module-__main__) module is a special case relative to Python’s import system. As noted [elsewhere](https://python-all.ru/3.12/reference/toplevel_components.html#programs), the `__main__` module is directly initialized at interpreter startup, much like [`sys`](https://python-all.ru/3.12/library/sys.html#module-sys) and [`builtins`](https://python-all.ru/3.12/library/builtins.html#module-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.379380### 5.8.1. \_\_main\_\_.\_\_spec\_\_381382В зависимости от того, как инициализируется [`__main__`](https://python-all.ru/3.12/library/__main__.html#module-__main__), `__main__.__spec__` устанавливается соответствующим образом или в `None`.383384Когда Python запускается с опцией [`-m`](https://python-all.ru/3.12/using/cmdline.html#cmdoption-m), `__spec__` устанавливается в спецификацию модуля соответствующего модуля или пакета. `__spec__` также заполняется, когда модуль `__main__` загружается при выполнении каталога, zip-файла или другой записи [`sys.path`](https://python-all.ru/3.12/library/sys.html#sys.path).385386In [the remaining cases](https://python-all.ru/3.12/using/cmdline.html#using-on-interface-options) `__main__.__spec__` is set to `None`, as the code used to populate the [`__main__`](https://python-all.ru/3.12/library/__main__.html#module-__main__) does not correspond directly with an importable module:387388- интерактивная подсказка389- [`-c`](https://python-all.ru/3.12/using/cmdline.html#cmdoption-c) опция390- запуск из stdin391- запуск напрямую из исходного или байт-код файла392393Обратите внимание, что `__main__.__spec__` всегда `None` в последнем случае, *даже если* файл технически можно импортировать напрямую как модуль. Используйте флаг [`-m`](https://python-all.ru/3.12/using/cmdline.html#cmdoption-m), если нужны корректные метаданные модуля в [`__main__`](https://python-all.ru/3.12/library/__main__.html#module-__main__).394395Также обратите внимание, что даже если `__main__` соответствует импортируемому модулю и `__main__.__spec__` установлено соответствующим образом, они всё равно считаются *отдельными* модулями. Это связано с тем, что блоки, защищённые проверками `if __name__ == "__main__":`, выполняются только тогда, когда модуль используется для заполнения пространства имён `__main__`, а не при обычном импорте.396397## 5.9. Ссылки398399Механизм импорта значительно изменился с первых дней Python. Оригинальная [спецификация пакетов](https://python-all.ru/3.12/reference/import.html) всё ещё доступна для чтения, хотя некоторые детали изменились после написания этого документа.400401Оригинальная спецификация для [`sys.meta_path`](https://python-all.ru/3.12/library/sys.html#sys.meta_path) была [**PEP 302**](https://python-all.ru/3.12/reference/import.html), с последующим расширением в [**PEP 420**](https://python-all.ru/3.12/reference/import.html).402403[**PEP 420**](https://python-all.ru/3.12/reference/import.html) представил [пространства имён пакетов](https://python-all.ru/3.12/glossary.html#term-namespace-package) для Python 3.3. [**PEP 420**](https://python-all.ru/3.12/reference/import.html) также представил протокол `find_loader()` как альтернативу `find_module()`.404405[**PEP 366**](https://python-all.ru/3.12/reference/import.html) описывает добавление атрибута `__package__` для явных относительных импортов в главных модулях.406407[**PEP 328**](https://python-all.ru/3.12/reference/import.html) ввёл абсолютные и явные относительные импорты и изначально предложил `__name__` для семантики, которую [**PEP 366**](https://python-all.ru/3.12/reference/import.html) в конечном итоге определил для `__package__`.408409[**PEP 338**](https://python-all.ru/3.12/reference/import.html) определяет выполнение модулей как сценариев.410411[**PEP 451**](https://python-all.ru/3.12/reference/import.html) добавляет инкапсуляцию состояния импорта для каждого модуля в объекты спецификации. Он также перекладывает большую часть шаблонных обязанностей загрузчиков обратно на механизм импорта. Эти изменения позволяют устаревание нескольких API в системе импорта, а также добавление новых методов для искателей и загрузчиков.412413Сноски414415\[[1](https://python-all.ru/3.12/reference/import.html#id1)\]416417См. [`types.ModuleType`](https://python-all.ru/3.12/library/types.html#types.ModuleType).418419\[[2](https://python-all.ru/3.12/reference/import.html#id3)\]420421Реализация importlib избегает прямого использования возвращаемого значения. Вместо этого она получает объект модуля, выполняя поиск имени модуля в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules). Косвенный эффект этого заключается в том, что импортированный модуль может заменить себя в [`sys.modules`](https://python-all.ru/3.12/library/sys.html#sys.modules). Это поведение, зависящее от реализации, которое не гарантируется в других реализациях Python.422