Относительный импорт в urllib3 - PullRequest
0 голосов
/ 18 октября 2018

Я изучаю, как Python загружает модули.

Я начинаю с requests, который загружает urllib3.

Я нашел эти строки :

from .packages.six.moves.http_client import (
  IncompleteRead as httplib_IncompleteRead
)

в файле с именем src/urllib3/exceptions.py

Этот импорт является относительным, поэтому я ищу папку src/urllib3/packages/six/moves/http_client.py или src/urllib3/packages/six/moves/http_client/__init__.py

Этифайлы не существуют.

К счастью src/urllib3/packages/six.py определяет новый загрузчик модулей, поэтому для импорта .packages.six.moves.http_client требуется http_client основной модуль python.

Но я не понимаю, какsrc/urllib3/packages/six.py загружен.Я не нашел такой импорт.

Есть ли способ узнать, какой модуль загружает src/urllib3/packages/six.py напрямую?

Я пробовал с __name__ глобальной переменной, как предложено здесь .Его значение равно urllib3.packages.six, но urllib3.packages не загружает этот файл.

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Одна особенность функции импорта в Python заключается в том, что она может импортировать не только сами модули, но и переменные, классы, функции (обычно пространства имен) из них.В этом примере вы указали:

from .packages.six.moves.http_client import (
  IncompleteRead as httplib_IncompleteRead
)

оператор импорта относится к перемещению переменной из модуля src/urllib3/packages/six.py, которая определена в строке 316 этого файла и назначена экземплярукласса _MovedItems :

moves = _MovedItems(__name__ + ".moves")

и http_client - это свойство или метод этого экземпляра класса

0 голосов
/ 18 октября 2018

Выражение from .packages.six.moves.http_client import ... вызывает загрузку .packages.six first .Python всегда загружает все пакеты в ссылке на вложенный пакет для модуля.

Таким образом, .packages.six.moves.http_client заставляет Python сначала искать urllib3.packages, затем urllib3.packages.six и так далее.Механизм импорта делает это путем поиска полного имени в sys.modules, а если его там нет, запускает поиск и загрузку модулей для каждого.

В первый раз, когда это происходит, sys.modules['urllib3.packages.six'] несуществует, механизм импорта находит файл urllib3/packages/six.py, импортирует, что за до он будет искать другие имена.

И, как вы обнаружили, сам процесс импорта six.py файл модуля, заставляет этот модуль добавлять sys.modules['urllib3.packages.six.moves'] и дальнейшие ссылки на стандартные библиотечные модули.

Механизм импорта Python - довольно сложный зверь;справочная документация Python охватывает это всесторонне в Система импорта ;конкретные записи для поиска:

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

и ниже Обычные пакеты

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

и Кэш модуля :

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

(жирный акцент в цитатных разделах добавлен мной).

Обратите внимание, что все в *Каталог 1075 * представляет собой вендор пакет;проект, который обычно устанавливается независимо, но проект urllib3 решил собрать в свой собственный дистрибутив, чтобы не волноваться о том, какие версии поддерживать.six - это такой независимый проект, вы можете установить его из PyPI .

Более подробную информацию о six.moves виртуальном пакете можно найти в six проектная документация .Его цель - облегчить разработчикам библиотек написание кода, совместимого как с Python 2, так и с Python 3, не беспокоясь о том, какое стандартное имя библиотеки импортировать в любую из версий.

...