sys.path
.sys.path_hooks
.sys.path_importer_cache
.sys.meta_path
.sys.path
:Атрибут sys.path
модуля sys
представляет собой список строк, который указывает путь поиска для модулей. Инициализируется из переменной среды PYTHONPATH
, а также зависит от установки по умолчанию.
Атрибут sys.path
инициализируется при запуске программы, первый элемент этого списка, path[0]
является каталогом, содержащим скрипт, который использовался для вызова интерпретатора Python. Если каталог скриптов недоступен, например если интерпретатор вызывается в интерактивном режиме или если скрипт читается из стандартного ввода, то path[0] является пустой строкой, которая в первую очередь направляет Python для поиска модулей в текущем каталоге. Обратите внимание, что каталог скриптов вставляется перед записями, вставленными из PYTHONPATH
.
Из кода можно свободно изменять этот список для своих собственных целей. В sys.path
должны быть добавлены только строки и байтовые строки, все остальные типы данных игнорируются при импорте.
Внимание!
sys.path
больше не принимает байтовые строки. Поддержка прекратилась где-то между Python 3.2 и 3.6, и никто этого не заметил, пока не вышел Python 3.10.
sys.path
:Путь поиска для модулей управляется как список Python, сохраненный в sys.path
. Содержимое пути по умолчанию включает каталог скрипта, используемого для запуска приложения и текущий рабочий каталог.
import sys for d in sys.path: print(d) # /home/docs-python/python-3.7.4/docs-python # /home/docs-python/python-3.7.4/docs-python/lib/python37.zip # /home/docs-python/python-3.7.4/docs-python/lib/python3.7 # /home/docs-python/python-3.7.4/docs-python/lib/python3.7/lib-dynload # /opt/python-3.7.4/lib/python3.7 # /home/docs-python/python-3.7.4/docs-python/lib/python3.7/site-packages
Из кода также можно добавить свой путь поиска модуля из нестандартного места, добавив новый путь непосредственно в sys.path
.
Создадим тестовый модуль test_md.py
, который сохраним в директории ./md/test_md.py
# test_md.py DATA = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Теперь импортируем тестовый модуль
import os import sys base_dir = os.path.dirname(__file__) or '.' print('Base directory:', base_dir) # добавление нового пути поиска dir_md = os.path.join(base_dir, 'md') sys.path.append(dir_md) import test_md print('Imported example from:', test_md.__file__) print(' ', test_md.DATA) # Base directory: . # Imported test_md from: ./md/test_md.py # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Изменение пути поиска позволяет контролировать поиск стандартных модулей Python. Но что, если программе необходимо импортировать код из файла, отличного от обычных файлов .py
или .pyc
в файловой системе? Ловушки импорта sys.path_hooks
решает эту проблему. Они могут перехватить попытку найти модуль в sys.path
и принять альтернативные меры для загрузки кода из другого места или применения к нему предварительной обработки.
sys.path_hooks
:Атрибут sys.path_hooks
содержит список вызываемых объектов, которые принимают путь - аргумент path
, чтобы попытаться создать искатель finder
для этого пути. Если искатель может быть создан, он должен быть возвращен вызываемым объектом, иначе необходимо вызвать исключение ImportError
.
Пользовательские импортеры реализуются в два отдельных этапа. Искатель отвечает за определение местоположения модуля и предоставление загрузчика для управления фактическим импортом. Пользовательские модули поиска добавляются путем добавления фабрики в список sys.path_hooks
. При импорте каждая часть пути передается искателю до тех пор, пока не будет заявлено о поддержке не вызывая исключение ImportError
. Затем этот искатель отвечает за поиск в хранилище данных, представленном его записью пути для именованных модулей.
sys.path_hooks
:Создадим тестовый модуль test_md.py
, который сохраним в директории ./md/test_md.py
# test_md.py DATA = [1, 2, 3, 4, 5, 6, 7, 8, 9]
import sys class ImportFinder: PATH_TRIGGER = './md' def __init__(self, path_entry): print(f'Checking {path_entry}:', end=' ') if path_entry != self.PATH_TRIGGER: print('wrong finder') raise ImportError() else: print('works') return def find_module(self, fullname, path=None): print('Looking for {!r}'.format(fullname)) return None sys.path_hooks.append(ImportFinder) for hook in sys.path_hooks: print(f'Path hook: {hook}') sys.path.insert(0, ImportFinder.PATH_TRIGGER) try: print('importing "test_md"') import test_md except Exception as e: print('Import failed:', e) # Path hook: <class 'zipimport.zipimporter'> # Path hook: <function FileFinder.path_hook.<locals>.path_hook_for_FileFinder at 0x7f3a6e4de3b0> # Path hook: <class '__main__.ImportFinder'> # importing "test_md"
sys.path_importer_cache
:Атрибут sys.path_importer_cache
представляет собой словарь, который выступает в качестве кэша для объектов поиска. Ключи - это пути, которые были переданы в систему sys.path_hooks
и значения - это найденные искатели. Если путь является допустимым путем файловой системы, но искатель не найден в системе, то тогда путь в sys.path_hooks
не сохраняется.
>>> import sys >>> sys.path_importer_cache # {'/home/docs-python/python-3.7.4/docs-python/lib/python37.zip': None, # '/home/docs-python/python-3.7.4/docs-python/lib/python3.7': FileFinder('/home/docs-python/python-3.7.4/docs-python/lib/python3.7'), # ... # ... # '/home/docs-python': FileFinder('/home/docs-python')}
sys.meta_path
:Атрибут sys.meta_path
представляет собой список объектов поиска мета-пути, у которых есть свои методы find_spec()
, вызываемые для определения, может ли один из объектов найти модуль для импорта.
Метод find_spec()
вызывается как минимум с абсолютным именем импортируемого модуля. Если импортируемый модуль содержится в пакете, то атрибут __path__
родительского пакета передается в качестве второго аргумента. Метод возвращает спецификацию модуля или None
, если модуль не может быть найден.
>>> import sys >>> sys.meta_path # [<class '_frozen_importlib.BuiltinImporter'>, # <class '_frozen_importlib.FrozenImporter'>, # <class '_frozen_importlib_external.PathFinder'>]