Документация Python неофициальный перевод
Содержание страницы

5. Система импортаThe import system

Код на Python в одном модуле получает доступ к коду в другом модуле через процесс импортирования. Оператор import – самый распространённый способ вызова механизма импорта, но не единственный. Такие функции, как importlib.import_module() и встроенная __import__(), также могут использоваться для вызова механизма импорта.

Оператор import объединяет две операции: он ищет указанный модуль, а затем привязывает результаты поиска к имени в локальной области видимости. Операция поиска оператора import определяется как вызов функции __import__() с соответствующими аргументами. Возвращаемое значение __import__() используется для выполнения операции привязки имени оператора import. См. оператор import для точных подробностей этой операции привязки имени.

Прямой вызов __import__() выполняет только поиск модуля и, если найден, операцию создания модуля. Хотя могут возникать некоторые побочные эффекты, такие как импорт родительских пакетов и обновление различных кешей (включая sys.modules), только оператор import выполняет операцию привязки имени.

При вызове __import__() как части оператора import система импорта сначала проверяет глобальное пространство имён модуля на наличие функции с таким именем. Если она не найдена, вызывается стандартная встроенная __import__(). Другие механизмы вызова системы импорта (например, importlib.import_module()) не выполняют эту проверку и всегда используют стандартную систему импорта.

Когда модуль импортируется впервые, Python ищет модуль и, если найден, создаёт объект модуля [1], инициализируя его. Если указанный модуль не найден, возбуждается ImportError. Python реализует различные стратегии поиска указанного модуля при вызове механизма импорта. Эти стратегии можно изменять и расширять с помощью различных хуков, описанных в следующих разделах.

Изменено в версии 3.3: Система импорта была обновлена для полной реализации второй фазы PEP 302. Больше нет неявного механизма импорта – полная система импорта раскрывается через sys.meta_path. Кроме того, реализована поддержка нативных пакетов пространств имён (см. PEP 420).

5.1. importlib

Модуль importlib предоставляет богатый API для взаимодействия с системой импорта. Например, importlib.import_module() предоставляет рекомендуемый, более простой API, чем встроенная __import__(), для вызова механизма импорта. Обратитесь к библиотечной документации importlib за дополнительными подробностями.

5.2. ПакетыPackages

Python has only one type of module object, and all modules are of this type, regardless of whether the module is implemented in Python, C, or something else. To help organize modules and provide a naming hierarchy, Python has a concept of packages.

Можно представлять пакеты как каталоги в файловой системе, а модули – как файлы в этих каталогах, но не стоит воспринимать эту аналогию слишком буквально, поскольку пакеты и модули не обязательно происходят из файловой системы. В целях данной документации мы будем использовать эту удобную аналогию каталогов и файлов. Как и каталоги файловой системы, пакеты организованы иерархически, и пакеты могут содержать вложенные пакеты, а также обычные модули.

Важно помнить, что все пакеты являются модулями, но не все модули являются пакетами. Или, другими словами, пакеты – это просто особый вид модуля. В частности, любой модуль, содержащий атрибут __path__, считается пакетом.

Все модули имеют имя. Имена подпакетов отделяются от имени родительского пакета точками, подобно стандартному синтаксису доступа к атрибутам Python. Таким образом, у вас может быть модуль с именем sys и пакет с именем email, который, в свою очередь, содержит подпакет email.mime и модуль внутри этого подпакета с именем email.mime.text.

5.2.1. Обычные пакетыRegular packages

Python определяет два типа пакетов: обычные пакеты и пакеты пространств имён. Обычные пакеты – это традиционные пакеты, существовавшие в Python 3.2 и ранее. Обычный пакет обычно реализуется как каталог, содержащий файл __init__.py. При импорте обычного пакета этот файл __init__.py неявно выполняется, и объекты, которые он определяет, привязываются к именам в пространстве имён пакета. Файл __init__.py может содержать тот же код Python, что и любой другой модуль, и Python добавит в модуль некоторые дополнительные атрибуты при его импорте.

Например, следующая структура файловой системы определяет пакет верхнего уровня parent с тремя подпакетами:

parent/
    __init__.py
    one/
        __init__.py
    two/
        __init__.py
    three/
        __init__.py

Импорт parent.one неявно выполнит parent/__init__.py и parent/one/__init__.py. Последующие импорты parent.two или parent.three выполнят parent/two/__init__.py и parent/three/__init__.py соответственно.

5.2.2. Пакеты пространства имёнNamespace packages

A namespace package is a composite of various portions, where each portion contributes a subpackage to the parent package. Portions may reside in different locations on the file system. Portions may also be found in zip files, on the network, or anywhere else that Python searches during import. Namespace packages may or may not correspond directly to objects on the file system; they may be virtual modules that have no concrete representation.

Пакеты пространств имён не используют обычный список для своего атрибута __path__. Вместо этого они используют пользовательский итерируемый тип, который автоматически выполняет новый поиск частей пакета при следующей попытке импорта внутри этого пакета, если путь родительского пакета (или sys.path для пакета верхнего уровня) изменяется.

В пакетах пространств имён нет файла parent/__init__.py. Фактически, при поиске импорта может быть найдено несколько каталогов parent, каждый из которых предоставляется разной частью. Таким образом, parent/one может физически не находиться рядом с parent/two. В этом случае Python создаст пакет пространства имён для пакета верхнего уровня parent всякий раз, когда импортируется он сам или один из его подпакетов.

See also PEP 420 for the namespace package specification.

5.3. ПоискSearching

Чтобы начать поиск, Python требуется полностью квалифицированное имя модуля (или пакета, но для целей данного обсуждения различие несущественно). Это имя может быть получено из различных аргументов оператора import или из параметров функций importlib.import_module() или __import__().

Это имя будет использоваться на разных этапах поиска импорта, и оно может быть точечным путём к подмодулю, например foo.bar.baz. В этом случае Python сначала пытается импортировать foo, затем foo.bar, и наконец foo.bar.baz. Если любой из промежуточных импортов завершается неудачей, возбуждается ImportError.

5.3.1. Кеш модулейThe module cache

Первое место, проверяемое во время поиска импорта – это sys.modules. Это отображение служит кешем всех ранее импортированных модулей, включая промежуточные пути. Так, если foo.bar.baz был ранее импортирован, sys.modules будет содержать записи для foo, foo.bar и foo.bar.baz. Каждый ключ будет иметь в качестве значения соответствующий объект модуля.

Во время импорта имя модуля ищется в sys.modules, и если оно присутствует, соответствующее значение является модулем, удовлетворяющим импорту, и процесс завершается. Однако если значение равно None, то возбуждается ImportError. Если имя модуля отсутствует, Python продолжит поиск модуля.

sys.modules доступен для записи. Удаление ключа может не уничтожить связанный модуль (поскольку другие модули могут содержать ссылки на него), но оно сделает запись в кеше для указанного модуля недействительной, что вынудит Python выполнить новый поиск этого модуля при следующем импорте. Ключу также можно присвоить значение None, что приведёт к тому, что следующий импорт модуля закончится ImportError.

Однако будьте осторожны: если сохранить ссылку на объект модуля, сделать недействительной его запись в кеше sys.modules, а затем повторно импортировать именованный модуль, эти два объекта модуля не будут одинаковыми. Напротив, imp.reload() будет повторно использовать тот же объект модуля и просто переинициализирует содержимое модуля, заново выполняя его код.

5.3.2. Искатели и загрузчикиFinders and loaders

Если указанный модуль не найден в sys.modules, то вызывается протокол импорта Python для поиска и загрузки модуля. Этот протокол состоит из двух концептуальных объектов: находителей и загрузчиков. Задача находителя – определить, может ли он найти указанный модуль, используя любую известную ему стратегию. Объекты, реализующие оба этих интерфейса, называются импортёрами – они возвращают себя, когда обнаруживают, что могут загрузить запрошенный модуль.

Python 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 for modules. The 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.

Механизм импорта является расширяемым, поэтому можно добавлять новые искатели для расширения диапазона и области поиска модулей.

Искатели на самом деле не загружают модули. Если им удается найти именованный модуль, они возвращают загрузчик, который затем вызывается механизмом импорта для загрузки модуля и создания соответствующего объекта модуля.

В следующих разделах протокол для искателей и загрузчиков описывается более подробно, включая то, как можно создавать и регистрировать новые для расширения механизма импорта.

5.3.3. Хуки импортаImport hooks

Механизм импорта разработан как расширяемый; основным механизмом для этого являются хуки импорта. Существует два типа хуков импорта: мета-хуки и хуки пути импорта.

Мета-хуки вызываются в начале обработки импорта, до того, как произойдёт любая другая обработка импорта, кроме поиска в кеше sys.modules. Это позволяет мета-хукам переопределять обработку sys.path, замороженные модули или даже встроенные модули. Мета-хуки регистрируются путём добавления новых объектов-находителей в sys.meta_path, как описано ниже.

Хуки путей импорта вызываются как часть обработки sys.path (или package.__path__) в точке, где встречается соответствующий элемент пути. Хуки путей импорта регистрируются путём добавления новых вызываемых объектов в sys.path_hooks, как описано ниже.

5.3.4. Мета-путьThe meta path

Если именованный модуль не найден в sys.modules, Python затем просматривает sys.meta_path, который содержит список объектов мета-искателей пути. Эти искатели опрашиваются по порядку, чтобы определить, знают ли они, как обрабатывать именованный модуль. Мета-искатели пути должны реализовывать метод find_module(), который принимает два аргумента: имя и путь импорта. Мета-искатель пути может использовать любую стратегию, чтобы определить, может ли он обработать именованный модуль.

Если мета-искатель пути знает, как обработать именованный модуль, он возвращает объект загрузчика. Если он не может обработать именованный модуль, он возвращает None. Если обработка sys.meta_path достигает конца списка, не вернув загрузчик, то возбуждается ImportError. Любые другие возникшие исключения просто распространяются вверх, прерывая процесс импорта.

Метод find_module() мета-искателей пути вызывается с двумя аргументами. Первый – это полное имя импортируемого модуля, например foo.bar.baz. Второй аргумент – это записи пути, используемые для поиска модуля. Для модулей верхнего уровня второй аргумент равен None, но для подмодулей или подпакетов второй аргумент – это значение атрибута __path__ родительского пакета. Если соответствующий атрибут __path__ недоступен, возбуждается ImportError.

Мета-путь может обходиться несколько раз для одного запроса импорта. Например, если предположить, что ни один из задействованных модулей еще не кеширован, импорт foo.bar.baz сначала выполнит импорт верхнего уровня, вызывая mpf.find_module("foo", None) для каждого мета-искателя пути (mpf). После импорта foo, будет импортирован foo.bar путем вторичного обхода мета-пути с вызовом mpf.find_module("foo.bar", foo.__path__). После импорта foo.bar, последний обход вызовет mpf.find_module("foo.bar.baz", foo.bar.__path__).

Некоторые мета-пути находители поддерживают только импорт верхнего уровня. Эти импортёры всегда возвращают None, если в качестве второго аргумента передаётся что-либо, кроме None.

Стандартный sys.meta_path Python содержит три мета-пути находителя: один, который знает, как импортировать встроенные модули, один, который знает, как импортировать замороженные модули, и один, который знает, как импортировать модули из пути импорта (т.е. находитель на основе пути).

5.4. ЗагрузчикиLoaders

Если и когда загрузчик модуля найден, вызывается его метод load_module() с одним аргументом – полным именем импортируемого модуля. Этот метод имеет несколько обязанностей и должен вернуть загруженный им объект модуля [2]. Если он не может загрузить модуль, он должен возбудить ImportError, хотя любые другие исключения, возникшие во время load_module(), будут распространены.

Во многих случаях искатель и загрузчик могут быть одним и тем же объектом; в таких случаях finder.find_module() просто вернет self.

Загрузчики должны удовлетворять следующим требованиям:

  • Если в sys.modules уже существует объект модуля с заданным именем, загрузчик должен использовать этот существующий модуль. (В противном случае imp.reload() не будет работать правильно.) Если именованный модуль не существует в sys.modules, загрузчик должен создать новый объект модуля и добавить его в sys.modules.

    Обратите внимание, что модуль должен существовать в sys.modules до того, как загрузчик выполнит код модуля. Это критически важно, поскольку код модуля может (прямо или косвенно) импортировать сам себя; предварительное добавление его в sys.modules предотвращает неограниченную рекурсию в худшем случае и многократную загрузку в лучшем.

    Если загрузка не удалась, загрузчик должен удалить все модули, которые он вставил в sys.modules, но он должен удалить только неудавшийся модуль, и только если загрузчик сам явно его загрузил. Любой модуль, уже находящийся в кеше sys.modules, и любой модуль, успешно загруженный как побочный эффект, должны оставаться в кеше.

  • Загрузчик может установить атрибут __file__ модуля. Если он установлен, значение этого атрибута должно быть строкой. Загрузчик может оставить __file__ неустановленным, если он не имеет смыслового значения (например, модуль, загруженный из базы данных). Если __file__ установлен, возможно, также уместно установить атрибут __cached__, который является путем к любой скомпилированной версии кода (например, файлу байт-кода). Для установки этого атрибута файл не обязательно должен существовать; путь может просто указывать, существовал ли бы скомпилированный файл (см. PEP 3147).

  • Загрузчик может установить атрибут __name__ модуля. Хотя это не обязательно, настоятельно рекомендуется устанавливать этот атрибут, чтобы repr() модуля был более информативным.

  • Если модуль является пакетом (обычным или пространства имен), загрузчик должен установить атрибут __path__ объекта модуля. Значение должно быть итерируемым, но может быть пустым, если __path__ не имеет для загрузчика дальнейшего значения. Если __path__ не пуст, при итерации он должен выдавать строки. Более подробная информация о семантике __path__ приведена ниже.

  • Атрибут __loader__ должен быть установлен в объект загрузчика, который загрузил модуль. Это в основном для интроспекции и перезагрузки, но может использоваться для дополнительной функциональности, специфичной для загрузчика, например, для получения данных, связанных с загрузчиком.

  • Атрибут __package__ модуля должен быть установлен. Его значение должно быть строкой, но может совпадать со значением __name__. Если атрибут установлен в None или отсутствует, система импорта заполнит его более подходящим значением. Когда модуль является пакетом, его значение __package__ должно быть установлено в его __name__. Когда модуль не является пакетом, __package__ должно быть установлено в пустую строку для модулей верхнего уровня или для подмодулей – в имя родительского пакета. См. PEP 366 для получения дополнительных сведений.

    Этот атрибут используется вместо __name__ для вычисления явных относительных импортов для главных модулей, как определено в PEP 366.

  • Если модуль является Python-модулем (в отличие от встроенного модуля или динамически загружаемого расширения), загрузчик должен выполнить код модуля в глобальном пространстве имён модуля (module.__dict__).

5.4.1. Представления модулейModule reprs

По умолчанию все модули имеют пригодное представление (repr), однако в зависимости от установленных выше атрибутов и хуков в загрузчике можно более явно управлять представлением объектов модуля.

Загрузчики могут реализовать метод module_repr(), который принимает один аргумент – объект модуля. Когда repr(module) вызывается для модуля с загрузчиком, поддерживающим этот протокол, все, что возвращается из module.__loader__.module_repr(module), возвращается в качестве представления модуля без дальнейшей обработки. Возвращаемое значение должно быть строкой.

Если у модуля нет атрибута __loader__ или у загрузчика нет метода module_repr(), то сама реализация объекта модуля создаст представление по умолчанию, используя любую доступную информацию. Она попытается использовать module.__name__, module.__file__ и module.__loader__ в качестве входных данных для представления, со значениями по умолчанию для отсутствующей информации.

Ниже приведены точные правила:

  • Если у модуля есть __loader__ и у этого загрузчика есть метод module_repr(), вызвать его с одним аргументом – объектом модуля. Возвращенное значение используется как представление модуля.
  • Если в module_repr() возникает исключение, оно перехватывается и отбрасывается, а вычисление представления модуля продолжается так, как если бы module_repr() не существовало.
  • Если у модуля есть атрибут __file__, он используется как часть repr модуля.
  • Если у модуля нет __file__, но есть __loader__, то представление загрузчика используется как часть представления модуля.
  • В противном случае в repr используется просто __name__ модуля.

Этот пример из PEP 420 показывает, как загрузчик может создать собственное представление модуля:

class NamespaceLoader:
    @classmethod
    def module_repr(cls, module):
        return "<module '{}' (namespace)>".format(module.__name__)

5.4.2. module.__path__

По определению, если модуль имеет атрибут __path__, он является пакетом, независимо от его значения.

Атрибут __path__ пакета используется при импорте его подпакетов. В механизме импорта он работает почти так же, как sys.path, то есть предоставляет список местоположений для поиска модулей во время импорта. Однако __path__ обычно гораздо более ограничен, чем sys.path.

__path__ должен быть итерируемым объектом со строками, но может быть пустым. Те же правила, что и для sys.path, применяются к __path__ пакета, а sys.path_hooks (описанные ниже) используются при обходе __path__ пакета.

Файл __init__.py пакета может устанавливать или изменять атрибут __path__ пакета, и это был типичный способ реализации пакетов пространств имен до PEP 420. С принятием PEP 420 пакеты пространств имен больше не нуждаются в предоставлении файлов __init__.py, содержащих только код манипуляции __path__; загрузчик пространств имен автоматически устанавливает __path__ правильно для пакета пространства имен.

5.5. Искатель на основе путиThe Path Based Finder

Как упоминалось ранее, Python поставляется с несколькими мета-искателями пути по умолчанию. Один из них, называемый поисковиком на основе пути, просматривает путь импорта, который содержит список записей пути. Каждая запись пути задает местоположение для поиска модулей.

Сам искатель на основе путей не знает, как импортировать что-либо. Вместо этого он обходит отдельные записи пути, связывая каждую из них с искателем записей пути, который знает, как обрабатывать этот конкретный тип пути.

Стандартный набор искателей записей пути реализует всю семантику поиска модулей в файловой системе, обрабатывая специальные типы файлов, такие как исходный код Python (файлы .py), байт-код Python (файлы .pyc и .pyo) и динамические библиотеки (например, файлы .so). Если это поддерживается модулем zipimport из стандартной библиотеки, стандартные искатели записей пути также обрабатывают загрузку всех этих типов файлов (кроме динамических библиотек) из zip-файлов.

Записи пути не обязаны ограничиваться расположениями в файловой системе. Они могут ссылаться на URL, запросы к базе данных или любые другие расположения, которые можно указать в виде строки.

Искатель на основе путей предоставляет дополнительные перехватчики и протоколы, позволяющие расширять и настраивать типы искомых записей пути. Например, если требуется поддерживать записи пути в виде сетевых URL, можно написать перехватчик, реализующий семантику HTTP для поиска модулей в вебе. Этот перехватчик (вызываемый объект) вернёт искатель записей пути, поддерживающий описанный ниже протокол, который затем будет использован для получения загрузчика модуля из веба.

Предупреждение: в этом и предыдущем разделах используется термин finder, различая их с помощью терминов meta path finder и path entry finder. Эти два типа искателей очень похожи, поддерживают похожие протоколы и работают схожим образом во время импорта, но важно помнить, что они незначительно различаются. В частности, мета-искатели путей работают в начале процесса импорта, начиная с обхода sys.meta_path.

Напротив, искатели записей пути в некотором смысле являются деталью реализации искателя на основе путей, и на самом деле, если бы искатель на основе путей был удалён из sys.meta_path, ни одна из семантик искателей записей пути не была бы вызвана.

5.5.1. Искатели записей путиPath entry finders

Поисковик на основе пути отвечает за поиск и загрузку модулей и пакетов Python, местоположение которых задается строковой записью пути. Большинство записей пути задают местоположения в файловой системе, но не обязаны ограничиваться этим.

Как мета-искатель пути, поисковик на основе пути реализует протокол find_module(), описанный ранее, однако он предоставляет дополнительные хуки, которые можно использовать для настройки того, как модули находятся и загружаются из пути импорта.

Three variables are used by the path based finder, sys.path, sys.path_hooks and sys.path_importer_cache. The __path__ attributes on package objects are also used. These provide additional ways that the import machinery can be customized.

sys.path содержит список строк, определяющих места поиска модулей и пакетов. Он инициализируется из переменной окружения PYTHONPATH и различных других значений по умолчанию, зависящих от установки и реализации. Записи в sys.path могут указывать на каталоги файловой системы, zip-файлы и потенциально другие «местоположения» (см. модуль site), которые следует искать для модулей, например URL-адреса или запросы к базе данных. В sys.path должны присутствовать только строки и байты; все остальные типы данных игнорируются. Кодировка байтовых записей определяется индивидуальными искателями записей пути.

Поисковик на основе путей является поисковиком метапути, поэтому механизм импорта начинает поиск по пути импорта с вызова метода find_module(), как описано ранее. Когда задан аргумент path для find_module(), он представляет собой список строковых путей для обхода – обычно это атрибут __path__ пакета при импорте внутри этого пакета. Если аргумент path равен None, это означает импорт верхнего уровня, и используется sys.path.

Поисковик на основе путей перебирает все записи в пути поиска и для каждой из них ищет подходящий поисковик записи пути. Поскольку это может быть дорогостоящей операцией (например, могут быть накладные расходы на вызов stat() при таком поиске), поисковик на основе путей ведёт кэш, сопоставляющий записи пути с поисковиками записей пути. Этот кэш хранится в sys.path_importer_cache (несмотря на название, в этом кэше хранятся объекты поисковиков, а не только объекты импортёров). Таким образом, дорогостоящий поиск поисковика записи пути для конкретного местоположения path entry выполняется только один раз. Пользовательский код может удалять записи кэша из sys.path_importer_cache, заставляя поисковик на основе путей выполнять поиск записи пути заново [3].

Если записи пути нет в кэше, поисковик на основе путей перебирает все вызываемые объекты в sys.path_hooks. Каждый обработчик записи пути из этого списка вызывается с одним аргументом – записью пути, которую нужно найти. Этот вызываемый объект может либо вернуть поисковик записи пути, способный обработать данную запись пути, либо возбудить ImportError. ImportError используется поисковиком на основе путей, чтобы сообщить, что обработчик не может найти поисковик записи пути для данной записи пути. Исключение игнорируется, и обход пути импорта продолжается. Обработчик должен ожидать строковый или байтовый объект; кодировка байтовых объектов определяется обработчиком (например, это может быть кодировка файловой системы, UTF-8 или что-то ещё), и если обработчик не может декодировать аргумент, он должен возбудить ImportError.

Если обход sys.path_hooks завершается без возврата поисковика записи пути, метод find_module() поисковика на основе путей сохранит None в sys.path_importer_cache (чтобы указать, что для этой записи пути нет поисковика) и вернёт None, показывая, что данный поисковик метапути не смог найти модуль.

If a path entry finder is returned by one of the path entry hook callables on sys.path_hooks, then the following protocol is used to ask the finder for a module loader, which is then used to load the module.

5.5.2. Протокол искателя записей путиPath entry finder protocol

Для поддержки импорта модулей и инициализированных пакетов, а также для внесения вклада в пространства имён пакетов, поисковики записей пути должны реализовывать метод find_loader().

find_loader() принимает один аргумент – полностью квалифицированное имя импортируемого модуля. find_loader() возвращает кортеж из двух элементов: первый – загрузчик, второй – часть пространства имён. Когда первый элемент (т.е. загрузчик) равен None, это означает, что, хотя поисковик записи пути не имеет загрузчика для указанного модуля, он знает, что данная запись пути вносит вклад в часть пространства имён для указанного модуля. Это почти всегда происходит, когда Python просят импортировать пакет пространства имён, не имеющий физического представления в файловой системе. Когда поисковик записи пути возвращает None в качестве загрузчика, второй элемент возвращаемого кортежа из двух элементов должен быть последовательностью, хотя она может быть пустой.

Если find_loader() возвращает значение загрузчика, отличное от None, порция игнорируется, и загрузчик возвращается из поисковика на основе путей, завершая поиск по записям пути.

Для обратной совместимости с другими реализациями протокола импорта многие поисковики пути также поддерживают тот же традиционный метод find_module(), который поддерживают мета-поисковики. Однако методы find_module() поисковика пути никогда не вызываются с аргументом path (ожидается, что они записывают соответствующую информацию о пути из начального вызова хука пути).

Метод find_module() у поисковиков записей пути является устаревшим, поскольку он не позволяет поисковику записи пути вносить вклад в пакеты пространств имён. Вместо этого поисковики записей пути должны реализовывать метод find_loader(), как описано выше. Если этот метод существует в поисковике записи пути, система импорта всегда будет вызывать find_loader() в предпочтение find_module().

5.6. Замена стандартной системы импортаReplacing the standard import system

Самый надёжный способ заменить всю систему импорта – это удалить содержимое по умолчанию sys.meta_path, полностью заменив его пользовательским хуком мета-пути.

Если допустимо изменить только поведение инструкций import без влияния на другие API, обращающиеся к системе импорта, то замена встроенной функции __import__() может быть достаточной. Этот приём также может применяться на уровне модуля для изменения только поведения инструкций import внутри этого модуля.

Чтобы выборочно предотвратить импорт некоторых модулей из обработчика на раннем этапе метапути (вместо полного отключения стандартной системы импорта), достаточно возбудить ImportError непосредственно из find_module(), а не возвращать None. Последнее означает, что поиск по метапути должен продолжаться, тогда как возбуждение исключения немедленно его прекращает.

5.7. Открытые вопросыOpen issues

XXX Очень хотелось бы иметь диаграмму.

XXX * (import_machinery.rst) как насчёт раздела, посвящённого только атрибутам модулей и пакетов, возможно, расширяющего или заменяющего соответствующие записи на странице справочника по модели данных?

XXX runpy, pkgutil и т.п. в библиотечном руководстве должны получить ссылки «См. также» в начале, указывающие на новый раздел о системе импорта.

5.8. СсылкиReferences

Механизм импорта значительно изменился с первых дней Python. Оригинальная спецификация пакетов всё ещё доступна для чтения, хотя некоторые детали изменились после написания этого документа.

Исходная спецификация sys.meta_path была PEP 302, с последующим расширением в PEP 420.

PEP 420 ввёл пакеты пространств имён для Python 3.3. PEP 420 также ввёл протокол find_loader() в качестве альтернативы find_module().

PEP 366 описывает добавление атрибута __package__ для явных относительных импортов в главных модулях.

PEP 328 ввёл абсолютные и явные относительные импорты и изначально предложил __name__ для семантики, которую PEP 366 в итоге определил для __package__.

PEP 338 определяет выполнение модулей как сценариев.

Сноски

[1]См. types.ModuleType.
[2]Реализация importlib избегает прямого использования возвращаемого значения. Вместо этого она получает объект модуля, выполняя поиск имени модуля в sys.modules. Косвенным следствием этого является то, что импортированный модуль может заменить себя в sys.modules. Это поведение, зависящее от реализации, которое не гарантируется в других реализациях Python.
[3]В устаревшем коде можно найти экземпляры imp.NullImporter в sys.path_importer_cache. Рекомендуется изменить код так, чтобы вместо этого использовался None. См. Перенос кода Python для получения дополнительных сведений.