Python путь поиска импорта: что происходит первым? - PullRequest
0 голосов
/ 25 июня 2018

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

С "Путь поиска модуля" :

Когдаимпортируется модуль с именем spam, интерпретатор сначала ищет встроенный модуль с таким именем.Если файл не найден, он ищет файл с именем spam.py в списке каталогов, заданных переменной sys.path.

Из «Кэш модуля» :

Первое место, проверенное при поиске импорта, - sys.modules.Это отображение служит кешем всех ранее импортированных модулей, включая промежуточные пути.

Что из этого является более точным представлением того, что происходит внутри системы импорта Python?Приведенная ниже логика говорит, что они не могут сосуществовать, поскольку sys.modules вполне может содержать модули, которые не являются встроенными, и может исключать некоторые модули, которые находятся.:

sys.modules - для уже импортированных модулей кэширования;Это явно не для хранения полного списка встроенных модулей.(Наиболее близким к этому, я думаю, является sys.built_in_modules, но он также не включает в себя материал с атрибутом .__file__, например math.)

Если я запускаю новый интерпретаторсеанс, sys.modules содержит большинство встроенных функций, но исключает некоторые вещи из sys.builtin_module_names: а именно, gc и time, среди других.Кроме того, вы можете импортировать сторонние пакеты, которые будут помещены в sys.modules, и в этот момент sys.modules больше не является словарем, содержащим только встроенные модули.Таким образом, все это, кажется, говорит: «sys.modules! = Встроенные модули».

Ответы [ 3 ]

0 голосов
/ 25 июня 2018

Вы смотрите на два совершенно разных источника информации: учебник и справочник по языку.


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

Если модуль уже находится в кеше, этот процесс не происходит.Это здесь не объясняется, поскольку это уже было рассмотрено в предыдущем разделе Подробнее о модулях :

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

...

Примечание. Из соображений эффективности каждый модуль импортируется только один раз за сеанс интерпретатора.

Это не объясняет механизм, с помощью которого это происходит, потому что это всего лишь учебник.


Между тем, в справочных документах для системы импорта, модуль Секция cache объясняет первое, что происходит с оператором import.

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

Последующие разделы - начиная со следующего раздела, Искатели и загрузчики - аналогично описывают детали того, как модуль найден, более строго и более подробно, чем раздел «Путь поиска модуля» учебного пособия:

Python включает в себя ряд искателей и импортеров по умолчанию.Первый знает, как найти встроенные модули, а второй знает, как найти замороженные модули.Третий искатель по умолчанию ищет пути импорта для модулей.

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


На самом деле, если вы распечатаете sys.meta_path при установке CPython 3.7 по умолчанию, что вы 'Вы увидите:

<class '_frozen_importlib.BuiltinImporter'>
<class '_frozen_importlib.FrozenImporter'>
<class '_frozen_importlib_external.PathFinder'>

(В IPython, или если вы импортировали что-то вроде six, которое помогает переименовывать модули, или если вы импортировали что-то вроде requests, которое встраивает модули с поддержкой версий, выУ меня будет пара дополнительных искателей.)

Это BuiltinImporter задокументировано в документации по importlib.(Если вам интересно, почему он не называется BuiltinFinder, то средство поиска, которое также имеет собственный загрузчик, называется импортером.) Что он на самом деле делает, так это просматривает sys.builtin_module_names и вызывает специфичную для реализации функциючтобы справиться с чем-либо найденным там.


В CPython 3.6 (извиняюсь за переход между 3,6 и 3,7, но это не должно иметь значения…), специфичная для реализации функция, которую он вызывает, _imp.create_builtin, и вы можете отследить вещи оттуда.

Но главное, на что нужно обратить внимание, это то, что не все в builtin_module_names на самом деле «встроено» в том смысле, что оно предварительноимпортирован.Например, при обычной установке вы, вероятно, увидите там _ast, но не sys.modules['_ast'].

Так что функция create_builtin (или, для другой реализации, все, что она использует для реализацииBuiltinImporter) должен иметь возможность импортировать модули / dll / pyd / dylib, поставляемые с Python.

0 голосов
/ 25 июня 2018

вам нужно различать sys.path и sys.modules

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

Когда я загружаю sys.path в блокнот jupyter, отображается словарь сопоставленных имен загруженных модулейв расположение файла -

{'IPython': <module 'IPython' from 'C:\\Users\\User\\Anaconda3\\lib\\site-packages\\IPython\\__init__.py'>,
 'IPython.core': <module 'IPython.core' from 'C:\\Users\\User\\Anaconda3\\lib\\site-packages\\IPython\\core\\__init__.py'>,.....}

Это мой кеш модуля, но когда я пытаюсь

sys.modules['numpy']

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-44b02d746fe5> in <module>()
----> 1 sys.modules['numpy']

KeyError: 'numpy'

Так как numpy отсутствует в моем кеше модуля,Я попрошу python искать его в фиксированном наборе каталогов, определенном в sys.path.Список строк, где я могу добавить или удалить пути, как я считаю нужным.

sys.path Список строк, в которых указывается путь поиска для модулей.Инициализируется из переменной среды PYTHONPATH, плюс зависящее от установки значение по умолчанию.

Если python находит библиотеку в моем наборе sys.path s;это создаст для него отображение в sys.modules для быстрого доступа в активной среде.

import numpy
sys.modules['numpy']
#<module 'numpy' from 'C:\\Users\\User\\Anaconda3\\lib\\site-packages\\numpy\\__init__.py'>
0 голосов
/ 25 июня 2018

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

...