importlib.md
1> **Источник:** https://python-all.ru/3.1/library/importlib.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 29.6. `importlib` – Реализация [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import)89Новое в версии 3.1.1011## 29.6.1. Введение1213Назначение пакета `importlib` двоякое. Во-первых, предоставить реализацию оператора [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import) (и, следовательно, функции [`__import__()`](https://python-all.ru/3.1/library/functions.html#__import__)) в исходном коде Python. Это даёт реализацию [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import), переносимую на любой интерпретатор Python. Также предоставляется эталонная реализация, которую легче понять, чем реализацию на любом другом языке программирования.1415Во-вторых, компоненты для реализации [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import) можно сделать доступными в этом пакете, что упрощает пользователям создание собственных пользовательских объектов (обобщённо называемых [*импортёрами*](https://python-all.ru/3.1/glossary.html#term-importer)) для участия в процессе импорта. Подробности о предоставлении пользовательских импортёров можно найти в [**PEP 302**](https://python-all.ru/3.1/library/importlib.html).1617> **См. также**18>19> **[*Оператор import*](https://python-all.ru/3.1/reference/simple_stmts.html#import)**20>21> Справочное руководство по оператору22>23> [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import)24>25> .26>27> **[Спецификация пакетов](https://python-all.ru/3.1/library/importlib.html)**28>29> Оригинальная спецификация пакетов. Некоторые аспекты семантики изменились с момента написания этого документа (например, перенаправление на основе30>31> `None`32>33> в34>35> [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules)36>37> ).38>39> **Функция [`__import__()`](https://python-all.ru/3.1/library/importlib.html#importlib.__import__)**40>41> Встроенная функция, для которой оператор42>43> [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import)44>45> является синтаксическим сахаром.46>47> **[**PEP 235**](https://python-all.ru/3.1/library/importlib.html)**48>49> Импорт на платформах, нечувствительных к регистру50>51> **[**PEP 263**](https://python-all.ru/3.1/library/importlib.html)**52>53> Определение кодировок исходного кода Python54>55> **[**PEP 302**](https://python-all.ru/3.1/library/importlib.html)**56>57> Новые хуки импорта.58>59> **[**PEP 328**](https://python-all.ru/3.1/library/importlib.html)**60>61> Импорт: многострочный и абсолютный/относительный62>63> **[**PEP 366**](https://python-all.ru/3.1/library/importlib.html)**64>65> Явные относительные импорты в главном модуле66>67> **[**PEP 3120**](https://python-all.ru/3.1/library/importlib.html)**68>69> Использование UTF-8 в качестве кодировки исходного кода по умолчанию7071## 29.6.2. Функции7273#### `importlib.__import__(name, globals={}, locals={}, fromlist=list(), level=0)`7475Реализация встроенной функции7677[`__import__()`](https://python-all.ru/3.1/library/functions.html#__import__)7879. Инструкции по использованию см. в документации встроенной функции.8081#### `importlib.import_module(name, package=None)`8283Импортирует модуль. Аргумент *name* задаёт импортируемый модуль в абсолютном или относительном виде (например, `pkg.mod` или `..mod`). Если имя указано в относительной форме, то аргумент *package* должен быть задан как имя пакета, который будет служить точкой привязки для разрешения имени пакета (например, `import_module('..mod', 'pkg.subpkg')` импортирует `pkg.mod`).8485Функция [`import_module()`](https://python-all.ru/3.1/library/importlib.html#importlib.import_module) действует как упрощающая обёртка вокруг [`importlib.__import__()`](https://python-all.ru/3.1/library/importlib.html#importlib.__import__). Это означает, что вся семантика функции выводится из [`importlib.__import__()`](https://python-all.ru/3.1/library/importlib.html#importlib.__import__), включая требование, чтобы пакет, из которого происходит импорт, был ранее импортирован (т.е. *package* должен быть уже импортирован). Самое важное отличие в том, что [`import_module()`](https://python-all.ru/3.1/library/importlib.html#importlib.import_module) возвращает самый вложенный пакет или модуль, который был импортирован (например, `pkg.mod`), в то время как [`__import__()`](https://python-all.ru/3.1/library/functions.html#__import__) возвращает пакет или модуль верхнего уровня (например, `pkg`).8687## 29.6.3. `importlib.abc` – Абстрактные базовые классы, связанные с импортом8889Модуль `importlib.abc` содержит все основные абстрактные базовые классы, используемые оператором [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import). Некоторые подклассы основных абстрактных базовых классов также предоставляются для помощи в реализации основных ABC.9091#### `class importlib.abc.Finder`9293Абстрактный базовый класс, представляющий [*искатель*](https://python-all.ru/3.1/glossary.html#term-finder). См. [**PEP 302**](https://python-all.ru/3.1/library/importlib.html) для точного определения искателя.9495#### `find_module(fullname, path=None)`9697Абстрактный метод для поиска9899[*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader)100101для указанного модуля. Если102103[*искатель*](https://python-all.ru/3.1/glossary.html#term-finder)104105найден в106107[`sys.meta_path`](https://python-all.ru/3.1/library/sys.html#sys.meta_path)108109и искомый модуль является подпакетом или модулем, то110111*path*112113будет значением114115`__path__`116117из родительского пакета. Если загрузчик не найден, возвращается118119`None`120121.122123#### `class importlib.abc.Loader`124125Абстрактный базовый класс для [*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader). См. [**PEP 302**](https://python-all.ru/3.1/library/importlib.html) для точного определения загрузчика.126127#### `load_module(fullname)`128129Абстрактный метод для загрузки модуля. Если модуль невозможно загрузить, возбуждается [`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError), иначе возвращается загруженный модуль.130131Если запрошенный модуль уже существует в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules), то он должен быть использован и перезагружен. В противном случае загрузчик должен создать новый модуль и вставить его в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules) до начала загрузки, чтобы предотвратить рекурсию при импорте. Если загрузчик вставил модуль, но загрузка завершилась неудачей, он должен удалить его из [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules); модули, уже находившиеся в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules) до начала выполнения загрузчика, следует оставить нетронутыми. Декоратор [`importlib.util.module_for_loader()`](https://python-all.ru/3.1/library/importlib.html#importlib.util.module_for_loader) обрабатывает все эти детали.132133Загрузчик должен установить несколько атрибутов модуля. (Обратите внимание, что некоторые из этих атрибутов могут измениться при перезагрузке модуля.)134135- **`__name__`**136137 Имя модуля.138- **`__file__`**139140 Путь к месту хранения данных модуля (не задан для встроенных модулей).141- **`__path__`**142143 Список строк, задающих путь поиска внутри пакета. Этот атрибут не задан для модулей.144- **`__package__`**145146 Родительский пакет для модуля/пакета. Если модуль находится на верхнем уровне, то его значением является пустая строка. Декоратор [`importlib.util.set_package()`](https://python-all.ru/3.1/library/importlib.html#importlib.util.set_package) может обработать детали для `__package__`.147- **`__loader__`**148149 Загрузчик, используемый для загрузки модуля. (Он не устанавливается встроенным механизмом импорта, но должен быть установлен при использовании [*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader).)150151#### `class importlib.abc.ResourceLoader`152153Абстрактный базовый класс для [*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader), который реализует опциональный протокол [**PEP 302**](https://python-all.ru/3.1/library/importlib.html) для загрузки произвольных ресурсов из бэкенда хранилища.154155#### `get_data(path)`156157Абстрактный метод, возвращающий байты данных по заданному пути158159*path*160161. Загрузчики, имеющие файлоподобное хранилище, позволяющее сохранять произвольные данные, могут реализовать этот абстрактный метод для прямого доступа к хранимым данным.162163[`IOError`](https://python-all.ru/3.1/library/exceptions.html#IOError)164165должно быть возбуждено, если166167*path*168169не найден. Ожидается, что170171*path*172173будет построен с использованием атрибута модуля174175`__file__`176177или элемента из178179`__path__`180181пакета.182183#### `class importlib.abc.InspectLoader`184185Абстрактный базовый класс для [*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader), который реализует опциональный протокол [**PEP 302**](https://python-all.ru/3.1/library/importlib.html) для загрузчиков, которые инспектируют модули.186187#### `get_code(fullname)`188189Абстрактный метод, возвращающий объект190191`code`192193для модуля. Если у модуля нет объекта кода (например, встроенный модуль), возвращается194195`None`196197. Возбуждается198199[`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError)200201, если загрузчик не может найти запрошенный модуль.202203#### `get_source(fullname)`204205Абстрактный метод, возвращающий исходный код модуля. Код возвращается в виде текстовой строки с универсальными переводами строк. Возвращает206207`None`208209, если исходный код недоступен (например, для встроенного модуля). Вызывает210211[`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError)212213, если загрузчик не может найти указанный модуль.214215#### `is_package(fullname)`216217Абстрактный метод, возвращающий истинное значение, если модуль является пакетом, и ложное в противном случае.218219[`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError)220221возбуждается, если222223[*загрузчик*](https://python-all.ru/3.1/glossary.html#term-loader)224225не может найти модуль.226227#### `class importlib.abc.PyLoader`228229Абстрактный базовый класс, наследующий от [`importlib.abc.InspectLoader`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.InspectLoader) и [`importlib.abc.ResourceLoader`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.ResourceLoader), предназначенный для упрощения загрузки модулей Python из исходного кода (байт-код не обрабатывается; см. [`importlib.abc.PyPycLoader`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.PyPycLoader) для ABC для исходного кода/байт-кода). Подклассу, реализующему этот ABC, нужно будет лишь позаботиться о том, как хранится исходный код; все остальные детали загрузки исходного кода Python будут обработаны конкретными реализациями ключевых методов.230231#### `source_path(fullname)`232233Абстрактный метод, возвращающий путь к исходному коду модуля. Должен возвращать234235`None`236237, если исходный код отсутствует. Вызывает238239[`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError)240241, если модуль не найден.242243#### `load_module(fullname)`244245Конкретная реализация246247[`importlib.abc.Loader.load_module()`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.Loader.load_module)248249, которая загружает исходный код Python. Вся необходимая информация поступает из абстрактных методов, требуемых этим ABC. Единственное существенное предположение, которое делает этот метод, заключается в том, что при загрузке пакета250251`__path__`252253устанавливается в254255`[os.path.dirname(__file__)]`256257.258259#### `get_code(fullname)`260261Конкретная реализация262263[`importlib.abc.InspectLoader.get_code()`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.InspectLoader.get_code)264265, которая создаёт объекты кода из исходного кода Python: запрашивает исходный код (с помощью266267[`source_path()`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.PyLoader.source_path)268269и270271`get_data()`272273), преобразует его в стандартные переводы строк и компилирует с помощью встроенной функции274275[`compile()`](https://python-all.ru/3.1/library/functions.html#compile)276277.278279#### `get_source(fullname)`280281Конкретная реализация282283[`importlib.abc.InspectLoader.get_source()`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.InspectLoader.get_source)284285. Использует286287[`importlib.abc.ResourceLoader.get_data()`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.ResourceLoader.get_data)288289и290291[`source_path()`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.PyLoader.source_path)292293для получения исходного кода. Также пытается угадать кодировку исходного кода с помощью294295[`tokenize.detect_encoding()`](https://python-all.ru/3.1/library/tokenize.html#tokenize.detect_encoding)296297.298299#### `class importlib.abc.PyPycLoader`300301Абстрактный базовый класс, наследующий от [`importlib.abc.PyLoader`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.PyLoader). Этот ABC предназначен для помощи в создании загрузчиков, поддерживающих как исходный код Python, так и байт-код.302303#### `source_mtime(fullname)`304305Абстрактный метод, который возвращает время изменения исходного кода указанного модуля. Время изменения должно быть целым числом. Если исходного кода нет, вернуть306307`None`308309. Если модуль не найден, возбуждается310311[`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError)312313.314315#### `bytecode_path(fullname)`316317Абстрактный метод, возвращающий путь к байт-коду указанного модуля, если он существует. Возвращает318319`None`320321, если байт-код (пока) отсутствует. Вызывает322323[`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError)324325, если модуль не найден.326327#### `write_bytecode(fullname, bytecode)`328329An abstract method which has the loader write330331*bytecode*332333for future use. If the bytecode is written, return334335`True`336337. Return338339`False`340341if the bytecode could not be written. This method should not be called if342343[`sys.dont_write_bytecode`](https://python-all.ru/3.1/library/sys.html#sys.dont_write_bytecode)344345is true. The346347*bytecode*348349argument should be a bytes string or bytes array.350351## 29.6.4. `importlib.machinery` – Импортеры и перехватчики путей352353Этот модуль содержит различные объекты, которые помогают [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import) находить и загружать модули.354355#### `class importlib.machinery.BuiltinImporter`356357An [*importer*](https://python-all.ru/3.1/glossary.html#term-importer) for built-in modules. All known built-in modules are listed in [`sys.builtin_module_names`](https://python-all.ru/3.1/library/sys.html#sys.builtin_module_names). This class implements the [`importlib.abc.Finder`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.Finder) and [`importlib.abc.InspectLoader`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.InspectLoader) ABCs.358359В этом классе определены только методы класса, чтобы не было необходимости в создании экземпляров.360361#### `class importlib.machinery.FrozenImporter`362363An [*importer*](https://python-all.ru/3.1/glossary.html#term-importer) for frozen modules. This class implements the [`importlib.abc.Finder`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.Finder) and [`importlib.abc.InspectLoader`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.InspectLoader) ABCs.364365В этом классе определены только методы класса, чтобы не было необходимости в создании экземпляров.366367#### `class importlib.machinery.PathFinder`368369[*Finder*](https://python-all.ru/3.1/glossary.html#term-finder) для [`sys.path`](https://python-all.ru/3.1/library/sys.html#sys.path). Этот класс реализует [`importlib.abc.Finder`](https://python-all.ru/3.1/library/importlib.html#importlib.abc.Finder) ABC.370371Этот класс не полностью отражает семантику [`import`](https://python-all.ru/3.1/reference/simple_stmts.html#import) в отношении [`sys.path`](https://python-all.ru/3.1/library/sys.html#sys.path). Не предполагается никаких неявных хуков путей для упрощения класса и его семантики.372373В этом классе определены только методы класса, чтобы избежать необходимости создания экземпляров.374375#### `classmethod find_module(fullname, path=None)`376377Метод класса, который пытается найти378379[*загрузчик*](https://python-all.ru/3.1/glossary.html#term-loader)380381для модуля, указанного в382383*fullname*384385, в386387[`sys.path`](https://python-all.ru/3.1/library/sys.html#sys.path)388389или, если задан, в390391*path*392393. Для каждой записи пути, которая просматривается,394395[`sys.path_importer_cache`](https://python-all.ru/3.1/library/sys.html#sys.path_importer_cache)396397проверяется. Если найден неложный объект, то он используется как398399[*finder*](https://python-all.ru/3.1/glossary.html#term-finder)400401для поиска модуля, который ищется. Если в402403[`sys.path_importer_cache`](https://python-all.ru/3.1/library/sys.html#sys.path_importer_cache)404405ничего не найдено, то406407[`sys.path_hooks`](https://python-all.ru/3.1/library/sys.html#sys.path_hooks)408409ищется на предмет finder для записи пути и, если найден, сохраняется в410411[`sys.path_importer_cache`](https://python-all.ru/3.1/library/sys.html#sys.path_importer_cache)412413, а также выполняется запрос относительно модуля. Если ни один finder не найден, возвращается414415`None`416417.418419## 29.6.5. `importlib.util` – Вспомогательный код для импортеров420421Этот модуль содержит различные объекты, помогающие в создании [*импортёра*](https://python-all.ru/3.1/glossary.html#term-importer).422423#### `importlib.util.module_for_loader(method)`424425[*Декоратор*](https://python-all.ru/3.1/glossary.html#term-decorator) для метода [*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader), чтобы выбрать подходящий объект модуля для загрузки. Декорированный метод должен иметь сигнатуру вызова с двумя позиционными аргументами (например, `load_module(self, module)`), где второй аргумент будет **объектом** модуля, который будет использоваться загрузчиком. Обратите внимание: декоратор не будет работать со статическими методами, так как предполагается два аргумента.426427Декорированный метод будет принимать **имя** модуля для загрузки, как и ожидается для [*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader). Если модуль не найден в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules), то создаётся новый с установленным атрибутом `__name__`. В противном случае модуль, найденный в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules), будет передан в метод. Если декорированный метод вызывает исключение и модуль был добавлен в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules), он будет удалён, чтобы не оставлять частично инициализированный модуль в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules). Если модуль уже был в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules), он остаётся нетронутым.428429Использование этого декоратора обрабатывает все детали того, какой объект модуля должен инициализировать загрузчик, как указано в [**PEP 302**](https://python-all.ru/3.1/library/importlib.html).430431#### `importlib.util.set_loader(fxn)`432433[*Декоратор*](https://python-all.ru/3.1/glossary.html#term-decorator)434435для метода436437[*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader)438439, который устанавливает атрибут440441`__loader__`442443на загруженных модулях. Если атрибут уже установлен, декоратор ничего не делает. Предполагается, что первый позиционный аргумент обёрнутого метода – это то, на что должен быть установлен444445`__loader__`446447.448449#### `importlib.util.set_package(fxn)`450451Декоратор [*декоратор*](https://python-all.ru/3.1/glossary.html#term-decorator) для [*загрузчика*](https://python-all.ru/3.1/glossary.html#term-loader), устанавливающий атрибут `__package__` на модуле, возвращаемом загрузчиком. Если `__package__` уже установлен и имеет значение, отличное от `None`, он не будет изменён. Обратите внимание, что атрибут устанавливается на модуле, возвращаемом загрузчиком, а не на модуле, найденном в [`sys.modules`](https://python-all.ru/3.1/library/sys.html#sys.modules).452453Полагаться на этот декоратор не рекомендуется, когда есть возможность установить `__package__` до начала выполнения кода. Устанавливая его до выполнения кода модуля, этот атрибут можно использовать на глобальном уровне модуля во время инициализации.454455## 29.6.6. Пример456457Ниже приведён пример импортера мета-пути, который использует словарь для хранения исходного кода. Хотя это не оптимальное решение – манипуляции с `__path__` пакетов не влияют на импорт – он показывает, насколько мало требуется для реализации импортера.458459```python460"""Импортёр, в котором исходный код хранится в словаре."""461from importlib import abc462463class DictImporter(abc.Finder, abc.PyLoader):464465 """Импортёр мета-пути, который хранит исходный код в словаре.466467 Ключи – имена модулей: пакеты должны заканчиваться на ``.__init__``.468 Значения должны быть тем, что можно передать в 'bytes'.469470 """471472 def __init__(self, memory):473 """Сохранить словарь."""474 self.memory = memory475476 def contains(self, name):477 """Проверить, есть ли модуль или пакет в словаре."""478 if name in self.memory:479 return name480 package_name = '{}.__init__'.format(name)481 if package_name in self.memory:482 return package_name483 return False484485 __contains__ = contains # Удобство.486487 def find_module(self, fullname, path=None):488 """Найти модуль в словаре."""489 if fullname in self:490 return self491 return None492493 def source_path(self, fullname):494 """Вернуть имя модуля, если он есть в словаре."""495 if not fullname in self:496 raise ImportError497 return fullname498499 def get_data(self, path):500 """Вернуть байты для исходного кода.501502 Значение, найденное в словаре, передаётся через 'bytes' перед тем, как503 возвращено.504505 """506 name = self.contains(path)507 if not name:508 raise IOError509 return bytes(self.memory[name])510511 def is_package(self, fullname):512 """Определить, является ли модуль пакетом, по тому, содержит ли словарь513 имя с добавленным в конце ``.__init__``."""514 if fullname not in self:515 raise ImportError516 if fullname in self.memory:517 return False518 # Если имя есть в этом импортёре, но не как есть, тогда оно должно заканчиваться на519 # ``__init__``.520 else:521 return True522```523