Содержание страницы
29.6. importlib – Реализация import¶importlib – An implementation of import
Новое в версии 3.1.
29.6.1. Введение¶Introduction
Назначение пакета importlib двоякое. Во-первых, предоставить реализацию оператора import (и, следовательно, функции __import__()) в исходном коде Python. Это даёт реализацию import, переносимую на любой интерпретатор Python. Также предоставляется эталонная реализация, которую легче понять, чем реализацию на любом другом языке программирования.
Во-вторых, компоненты для реализации import можно сделать доступными в этом пакете, что упрощает пользователям создание собственных пользовательских объектов (обобщённо называемых импортёрами) для участия в процессе импорта. Подробности о предоставлении пользовательских импортёров можно найти в PEP 302.
См. также
- Оператор import
- Справочное руководство по оператору import.
- Спецификация пакетов
- Оригинальная спецификация пакетов. Некоторые аспекты семантики изменились с момента написания этого документа (например, перенаправление на основе None в sys.modules).
- Функция __import__()
- Встроенная функция, для которой оператор import является синтаксическим сахаром.
- PEP 235
- Импорт на платформах, нечувствительных к регистру
- PEP 263
- Определение кодировок исходного кода Python
- PEP 302
- Новые хуки импорта.
- PEP 328
- Импорт: многострочный и абсолютный/относительный
- PEP 366
- Явные относительные импорты в главном модуле
- PEP 3120
- Использование UTF-8 в качестве кодировки исходного кода по умолчанию
29.6.2. Функции¶Functions
- importlib.__import__(name, globals={}, locals={}, fromlist=list(), level=0)¶
- Реализация встроенной функции __import__(). Инструкции по использованию см. в документации встроенной функции.
- importlib.import_module(name, package=None)¶
Импортирует модуль. Аргумент name задаёт импортируемый модуль в абсолютном или относительном виде (например, pkg.mod или ..mod). Если имя указано в относительной форме, то аргумент package должен быть задан как имя пакета, который будет служить точкой привязки для разрешения имени пакета (например, import_module('..mod', 'pkg.subpkg') импортирует pkg.mod).
Функция import_module() действует как упрощающая обёртка вокруг importlib.__import__(). Это означает, что вся семантика функции выводится из importlib.__import__(), включая требование, чтобы пакет, из которого происходит импорт, был ранее импортирован (т.е. package должен быть уже импортирован). Самое важное отличие в том, что import_module() возвращает самый вложенный пакет или модуль, который был импортирован (например, pkg.mod), в то время как __import__() возвращает пакет или модуль верхнего уровня (например, pkg).
29.6.3. importlib.abc – Абстрактные базовые классы, связанные с импортом¶importlib.abc – Abstract base classes related to import
Модуль importlib.abc содержит все основные абстрактные базовые классы, используемые оператором import. Некоторые подклассы основных абстрактных базовых классов также предоставляются для помощи в реализации основных ABC.
- class importlib.abc.Finder¶
Абстрактный базовый класс, представляющий искатель. См. PEP 302 для точного определения искателя.
- find_module(fullname, path=None)¶
- Абстрактный метод для поиска загрузчика для указанного модуля. Если искатель найден в sys.meta_path и искомый модуль является подпакетом или модулем, то path будет значением __path__ из родительского пакета. Если загрузчик не найден, возвращается None.
- class importlib.abc.Loader¶
Абстрактный базовый класс для загрузчика. См. PEP 302 для точного определения загрузчика.
- load_module(fullname)¶
Абстрактный метод для загрузки модуля. Если модуль невозможно загрузить, возбуждается ImportError, иначе возвращается загруженный модуль.
Если запрошенный модуль уже существует в sys.modules, то он должен быть использован и перезагружен. В противном случае загрузчик должен создать новый модуль и вставить его в sys.modules до начала загрузки, чтобы предотвратить рекурсию при импорте. Если загрузчик вставил модуль, но загрузка завершилась неудачей, он должен удалить его из sys.modules; модули, уже находившиеся в sys.modules до начала выполнения загрузчика, следует оставить нетронутыми. Декоратор importlib.util.module_for_loader() обрабатывает все эти детали.
Загрузчик должен установить несколько атрибутов модуля. (Обратите внимание, что некоторые из этих атрибутов могут измениться при перезагрузке модуля.)
- __name__
Имя модуля.
- __file__
Путь к месту хранения данных модуля (не задан для встроенных модулей).
- __path__
Список строк, задающих путь поиска внутри пакета. Этот атрибут не задан для модулей.
- __package__
Родительский пакет для модуля/пакета. Если модуль находится на верхнем уровне, то его значением является пустая строка. Декоратор importlib.util.set_package() может обработать детали для __package__.
- __loader__
Загрузчик, используемый для загрузки модуля. (Он не устанавливается встроенным механизмом импорта, но должен быть установлен при использовании загрузчика.)
- class importlib.abc.ResourceLoader¶
Абстрактный базовый класс для загрузчика, который реализует опциональный протокол PEP 302 для загрузки произвольных ресурсов из бэкенда хранилища.
- get_data(path)¶
- Абстрактный метод, возвращающий байты данных по заданному пути path. Загрузчики, имеющие файлоподобное хранилище, позволяющее сохранять произвольные данные, могут реализовать этот абстрактный метод для прямого доступа к хранимым данным. IOError должно быть возбуждено, если path не найден. Ожидается, что path будет построен с использованием атрибута модуля __file__ или элемента из __path__ пакета.
- class importlib.abc.InspectLoader¶
Абстрактный базовый класс для загрузчика, который реализует опциональный протокол PEP 302 для загрузчиков, которые инспектируют модули.
- get_code(fullname)¶
- Абстрактный метод, возвращающий объект code для модуля. Если у модуля нет объекта кода (например, встроенный модуль), возвращается None. Возбуждается ImportError, если загрузчик не может найти запрошенный модуль.
- get_source(fullname)¶
- Абстрактный метод, возвращающий исходный код модуля. Код возвращается в виде текстовой строки с универсальными переводами строк. Возвращает None, если исходный код недоступен (например, для встроенного модуля). Вызывает ImportError, если загрузчик не может найти указанный модуль.
- is_package(fullname)¶
- Абстрактный метод, возвращающий истинное значение, если модуль является пакетом, и ложное в противном случае. ImportError возбуждается, если загрузчик не может найти модуль.
- class importlib.abc.PyLoader¶
Абстрактный базовый класс, наследующий от importlib.abc.InspectLoader и importlib.abc.ResourceLoader, предназначенный для упрощения загрузки модулей Python из исходного кода (байт-код не обрабатывается; см. importlib.abc.PyPycLoader для ABC для исходного кода/байт-кода). Подклассу, реализующему этот ABC, нужно будет лишь позаботиться о том, как хранится исходный код; все остальные детали загрузки исходного кода Python будут обработаны конкретными реализациями ключевых методов.
- source_path(fullname)¶
- Абстрактный метод, возвращающий путь к исходному коду модуля. Должен возвращать None, если исходный код отсутствует. Вызывает ImportError, если модуль не найден.
- load_module(fullname)¶
- Конкретная реализация importlib.abc.Loader.load_module(), которая загружает исходный код Python. Вся необходимая информация поступает из абстрактных методов, требуемых этим ABC. Единственное существенное предположение, которое делает этот метод, заключается в том, что при загрузке пакета __path__ устанавливается в [os.path.dirname(__file__)].
- get_code(fullname)¶
- Конкретная реализация importlib.abc.InspectLoader.get_code(), которая создаёт объекты кода из исходного кода Python: запрашивает исходный код (с помощью source_path() и get_data()), преобразует его в стандартные переводы строк и компилирует с помощью встроенной функции compile().
- get_source(fullname)¶
- Конкретная реализация importlib.abc.InspectLoader.get_source(). Использует importlib.abc.ResourceLoader.get_data() и source_path() для получения исходного кода. Также пытается угадать кодировку исходного кода с помощью tokenize.detect_encoding().
- class importlib.abc.PyPycLoader¶
Абстрактный базовый класс, наследующий от importlib.abc.PyLoader. Этот ABC предназначен для помощи в создании загрузчиков, поддерживающих как исходный код Python, так и байт-код.
- source_mtime(fullname)¶
- Абстрактный метод, который возвращает время изменения исходного кода указанного модуля. Время изменения должно быть целым числом. Если исходного кода нет, вернуть None. Если модуль не найден, возбуждается ImportError.
- bytecode_path(fullname)¶
- Абстрактный метод, возвращающий путь к байт-коду указанного модуля, если он существует. Возвращает None, если байт-код (пока) отсутствует. Вызывает ImportError, если модуль не найден.
- write_bytecode(fullname, bytecode)¶
- An abstract method which has the loader write bytecode for future use. If the bytecode is written, return True. Return False if the bytecode could not be written. This method should not be called if sys.dont_write_bytecode is true. The bytecode argument should be a bytes string or bytes array.
29.6.4. importlib.machinery – Импортеры и перехватчики путей¶importlib.machinery – Importers and path hooks
Этот модуль содержит различные объекты, которые помогают import находить и загружать модули.
- class importlib.machinery.BuiltinImporter¶
An importer for built-in modules. All known built-in modules are listed in sys.builtin_module_names. This class implements the importlib.abc.Finder and importlib.abc.InspectLoader ABCs.
В этом классе определены только методы класса, чтобы не было необходимости в создании экземпляров.
- class importlib.machinery.FrozenImporter¶
An importer for frozen modules. This class implements the importlib.abc.Finder and importlib.abc.InspectLoader ABCs.
В этом классе определены только методы класса, чтобы не было необходимости в создании экземпляров.
- class importlib.machinery.PathFinder¶
Finder для sys.path. Этот класс реализует importlib.abc.Finder ABC.
Этот класс не полностью отражает семантику import в отношении sys.path. Не предполагается никаких неявных хуков путей для упрощения класса и его семантики.
В этом классе определены только методы класса, чтобы избежать необходимости создания экземпляров.
- classmethod find_module(fullname, path=None)¶
- Метод класса, который пытается найти загрузчик для модуля, указанного в fullname, в sys.path или, если задан, в path. Для каждой записи пути, которая просматривается, sys.path_importer_cache проверяется. Если найден неложный объект, то он используется как finder для поиска модуля, который ищется. Если в sys.path_importer_cache ничего не найдено, то sys.path_hooks ищется на предмет finder для записи пути и, если найден, сохраняется в sys.path_importer_cache, а также выполняется запрос относительно модуля. Если ни один finder не найден, возвращается None.
29.6.5. importlib.util – Вспомогательный код для импортеров¶importlib.util – Utility code for importers
Этот модуль содержит различные объекты, помогающие в создании импортёра.
- importlib.util.module_for_loader(method)¶
Декоратор для метода загрузчика, чтобы выбрать подходящий объект модуля для загрузки. Декорированный метод должен иметь сигнатуру вызова с двумя позиционными аргументами (например, load_module(self, module)), где второй аргумент будет объектом модуля, который будет использоваться загрузчиком. Обратите внимание: декоратор не будет работать со статическими методами, так как предполагается два аргумента.
Декорированный метод будет принимать имя модуля для загрузки, как и ожидается для загрузчика. Если модуль не найден в sys.modules, то создаётся новый с установленным атрибутом __name__. В противном случае модуль, найденный в sys.modules, будет передан в метод. Если декорированный метод вызывает исключение и модуль был добавлен в sys.modules, он будет удалён, чтобы не оставлять частично инициализированный модуль в sys.modules. Если модуль уже был в sys.modules, он остаётся нетронутым.
Использование этого декоратора обрабатывает все детали того, какой объект модуля должен инициализировать загрузчик, как указано в PEP 302.
- importlib.util.set_loader(fxn)¶
- Декоратор для метода загрузчика, который устанавливает атрибут __loader__ на загруженных модулях. Если атрибут уже установлен, декоратор ничего не делает. Предполагается, что первый позиционный аргумент обёрнутого метода – это то, на что должен быть установлен __loader__.
- importlib.util.set_package(fxn)¶
Декоратор декоратор для загрузчика, устанавливающий атрибут __package__ на модуле, возвращаемом загрузчиком. Если __package__ уже установлен и имеет значение, отличное от None, он не будет изменён. Обратите внимание, что атрибут устанавливается на модуле, возвращаемом загрузчиком, а не на модуле, найденном в sys.modules.
Полагаться на этот декоратор не рекомендуется, когда есть возможность установить __package__ до начала выполнения кода. Устанавливая его до выполнения кода модуля, этот атрибут можно использовать на глобальном уровне модуля во время инициализации.
29.6.6. Пример¶Example
Ниже приведён пример импортера мета-пути, который использует словарь для хранения исходного кода. Хотя это не оптимальное решение – манипуляции с __path__ пакетов не влияют на импорт – он показывает, насколько мало требуется для реализации импортера.
"""Импортёр, в котором исходный код хранится в словаре."""
from importlib import abc
class DictImporter(abc.Finder, abc.PyLoader):
"""Импортёр мета-пути, который хранит исходный код в словаре.
Ключи – имена модулей: пакеты должны заканчиваться на ``.__init__``.
Значения должны быть тем, что можно передать в 'bytes'.
"""
def __init__(self, memory):
"""Сохранить словарь."""
self.memory = memory
def contains(self, name):
"""Проверить, есть ли модуль или пакет в словаре."""
if name in self.memory:
return name
package_name = '{}.__init__'.format(name)
if package_name in self.memory:
return package_name
return False
__contains__ = contains # Удобство.
def find_module(self, fullname, path=None):
"""Найти модуль в словаре."""
if fullname in self:
return self
return None
def source_path(self, fullname):
"""Вернуть имя модуля, если он есть в словаре."""
if not fullname in self:
raise ImportError
return fullname
def get_data(self, path):
"""Вернуть байты для исходного кода.
Значение, найденное в словаре, передаётся через 'bytes' перед тем, как
возвращено.
"""
name = self.contains(path)
if not name:
raise IOError
return bytes(self.memory[name])
def is_package(self, fullname):
"""Определить, является ли модуль пакетом, по тому, содержит ли словарь
имя с добавленным в конце ``.__init__``."""
if fullname not in self:
raise ImportError
if fullname in self.memory:
return False
# Если имя есть в этом импортёре, но не как есть, тогда оно должно заканчиваться на
# ``__init__``.
else:
return True