В Python, когда вы импортируете модуль, интерпретатор выполняет следующие шаги:
-
Поиск модуля: Python ищет модуль в определенном порядке, используя список путей поиска, хранящийся в `sys.path`. Этот список включает текущий каталог, пути, указанные в переменной окружения `PYTHONPATH`, и каталог установки Python.
-
Компиляция (если необходимо): Если модуль является исходным файлом (`.py`), и с момента его последнего изменения версия скомпилированного байт-кода (`.pyc` или `.pyo`) устарела или отсутствует, Python сначала компилирует исходный файл в байт-код. Скомпилированный байт-код сохраняется в файле `.pyc` (или `.pyo` при использовании оптимизации).
-
Загрузка и выполнение: Python загружает скомпилированный байт-код (или выполняет исходный файл, если компиляция не требуется) и создает объект модуля. Этот объект модуля содержит все глобальные переменные, функции и классы, определенные в модуле.
Кэширование модулей: Самое важное для понимания здесь – это то, что Python кэширует загруженные модули в словаре `sys.modules`. `sys.modules` - это словарь, где ключами являются имена модулей, а значениями - соответствующие объекты модулей.
Повторный импорт: Когда вы повторно импортируете тот же модуль, Python сначала проверяет `sys.modules`. Если модуль уже находится там, Python не выполняет поиск, компиляцию и загрузку модуля снова. Вместо этого, он просто возвращает существующий объект модуля из `sys.modules`. Это существенно повышает производительность, особенно для больших и сложных модулей.
Важные моменты:
-
Кэширование происходит на уровне *объекта модуля*. Если вы измените исходный файл модуля, эти изменения не будут автоматически отражены, если вы просто повторно импортируете модуль.
-
Чтобы обновить модуль после внесения изменений, нужно использовать функцию `importlib.reload(module_object)`, где `module_object` - это объект модуля, который нужно перезагрузить. `importlib.reload()` удалит модуль из `sys.modules` и снова загрузит его, выполнив компиляцию, если исходный файл был изменен.
-
Удаление модуля из `sys.modules` (например, с помощью `del sys.modules['module_name']`) приводит к тому, что при следующем импорте модуль будет загружен заново. Однако, обычно это не рекомендуется делать, так как это может привести к неожиданным побочным эффектам.
-
Модули загружаются только один раз на интерпретатор Python (в рамках одного сеанса).
В заключение, кэширование модулей в `sys.modules` - это ключевой механизм, обеспечивающий эффективность импорта модулей в Python. Он предотвращает повторную загрузку и выполнение одного и того же модуля, пока не будет явно запрошено обновление с помощью `importlib.reload()`.