На PyCon US 2026 Руководящий совет Python рассказал о новых возможностях Python 3.15. Среди них — явные ленивые импорты (PEP 810): модули теперь можно загружать не при старте программы, а только в момент первого обращения. Я решил разобраться, как это работает, и измерить производительность в PyCharm.


В статье используется PyCharm. С 2022 года JetBrains не продаёт лицензии российским пользователям, поэтому без "танцев с бубном" получить полноценную поддержку не получится.

OpenIDE поддерживает не только Python, но и Java, Spring, Go, PHP, JavaScript и TypeScript! А полноценный DB-клиент, поддержка Docker и 300+ плагинов доступны абсолютно бесплатно в маркетплейсе.

Что такое явные ленивые импорты

PEP 810 вводит ключевое слово lazy для объявления отложенных импортов. Стандартный импорт выполняется сразу при запуске файла — ленивый откладывает загрузку модуля до первого обращения к его атрибутам.

Это сокращает время старта приложения и уменьшает потребление памяти. В большом CLI-инструменте или приложении с десятками библиотек разница ощутима.

Реализация построена на прокси-объектах в пространстве имён модуля — без изменений в базовых структурах данных интерпретатора. Это сохраняет существующие оптимизации CPython. Поиск и загрузка модуля откладываются вместе — это важно для файловых систем с высокой задержкой.

Для обратной совместимости PEP предусматривает глобальные управляющие флаги и переходную переменную.


Установка Python 3.15.0b1

На момент написания статьи Python 3.15.0b1 уже доступен. Проще всего установить его через uv или pyenv.

Убедитесь, что у вас последняя версия uv или pyenv, затем выполните одну из команд:

uv python install 3.15.0b1
pyenv install 3.15.0b1
Установка Python 3.15 через uv или pyenv
Установка Python 3.15 через uv или pyenv

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


Профилирование: обычный импорт vs ленивый

В среде data science принято начинать каждый скрипт с import pandas as pd и import numpy as np — даже если они не нужны. Допустим, вы получили от коллеги такой файл:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

def main():
    print("Initializing example data science project...")
    
    # Генерируем тестовые данные
    data = {
        'x': np.linspace(0, 10, 100),
        'y': np.sin(np.linspace(0, 10, 100)) + np.random.normal(0, 0.1, 100)
    }
    
    # Строим график
    plt.figure(figsize=(10, 6))
    plt.plot(data['x'], data['y'], label='Sine Wave with Noise')
    plt.title('Sample Visualization')
    plt.xlabel('X-axis')
    plt.ylabel('Y-axis')
    plt.legend()
    
    # Сохраняем файл (неинтерактивный режим)
    plt.savefig('sine_wave.png')
    print("Project executed successfully. Plot saved as sine_wave.png.")

if __name__ == "__main__":
    main()

PyCharm подсвечивает неиспользуемый pandas — убрать его легко. Но для эксперимента оставим его.

Чтобы наглядно увидеть профиль импортов, установите пакет tuna:

pip install tuna

Запустите профилирование через кастомный скрипт запуска:

python -X importtime main.py 2> import_log.txt; tuna import_log.txt

В браузере откроется граф импортов.

Граф импортов с обычными импортами — pandas занимает половину времени загрузки
Граф импортов с обычными импортами — pandas занимает половину времени загрузки

pandas занимает половину всего времени загрузки, хотя в этом скрипте не используется.

Теперь добавим lazy ко всем импортам:

lazy import pandas as pd
lazy import matplotlib.pyplot as plt
lazy import numpy as np
Код с ленивыми импортами — PyCharm пока не выделяет новый синтаксис
Код с ленивыми импортами — PyCharm пока не выделяет новый синтаксис

PyCharm пока не подсвечивает lazy — это новое ключевое слово, не вошедшее в релиз.

Снова запустим профилирование.

Граф импортов после применения lazy — pandas исчез из дерева загрузки
Граф импортов после применения lazy — pandas исчез из дерева загрузки

pandas исчез из графа. Суммарное время загрузки модулей сократилось заметно.

Если скрипт подключает много крупных библиотек, которые нужны лишь в некоторых ветках (например, в блоках if/else), ленивые импорты загрузят их только при реальном обращении.


Как ленивые импорты работают внутри

Когда модуль объявлен как lazy, вместо обычного import вызывается __lazy_import__. Создаётся прокси-объект types.LazyImportType, а имя модуля попадает в sys.lazy_modules вместо sys.modules. Подробнее — в разделе Lazy import mechanism PEP 810.

Когда прокси-объект используется впервые, CPython выполняет реальный импорт (reification): вызывает import, заменяет прокси настоящим модулем и убирает его из sys.lazy_modules.

Если при reification возникает ошибка, прокси остаётся. При следующем обращении попытка повторяется. В трейсбеке будут указаны оба места: где объявлен ленивый импорт и где произошло обращение. Подробнее — в разделе Reification PEP 810.

Исследуем в отладчике

Добавим точки остановки через pdb:

import pdb
pdb.set_trace()
lazy import pandas as pd
lazy import matplotlib.pyplot as plt
lazy import numpy as np
pdb.set_trace()
# ... остальной код

И ещё две точки — вокруг первого использования numpy и matplotlib:

    # Генерируем данные
    data = {
        'x': np.linspace(0, 10, 100),
        'y': np.sin(np.linspace(0, 10, 100)) + np.random.normal(0, 0.1, 100)
    }
    pdb.set_trace()
    
    # Строим график
    plt.figure(figsize=(10, 6))
    pdb.set_trace()
    # ...

Запускаем из консоли:

python main.py

PyCharm пока что не поддерживает Python 3.15, поэтому кнопки Run и Debug могут вести себя непредсказуемо с ленивыми импортами. Используйте консоль.

Первая точка остановки — до объявления импортов. Проверяем:

(Pdb) import sys
(Pdb) sys.lazy_modules
sys.lazy_modules пуст до объявления импортов
sys.lazy_modules пуст до объявления импортов

Список пуст — ни pandas, ни numpy, ни matplotlib не загружены.

Вторая точка — после объявления ленивых импортов. Снова проверяем:

(Pdb) sys.lazy_modules
sys.lazy_modules содержит pandas, numpy, matplotlib
sys.lazy_modules содержит pandas, numpy, matplotlib

Все три модуля появились в sys.lazy_modules. Проверяем, есть ли pandas в sys.modules:

(Pdb) 'pandas' in sys.modules
pandas в sys.modules — False
pandas в sys.modules — False

False. То же самое — для numpy и matplotlib.

Третья точка — после первого использования numpy. Проверяем sys.lazy_modules:

numpy удалён из sys.lazy_modules после первого использования
numpy удалён из sys.lazy_modules после первого использования

numpy исчез из sys.lazy_modules. Теперь он в sys.modulesTrue.

pandas и matplotlib по-прежнему не загружены.

Четвёртая точка — после первого использования matplotlib:

matplotlib удалён из sys.lazy_modules
matplotlib удалён из sys.lazy_modules

matplotlib также перешёл из sys.lazy_modules в sys.modules.

pandas не используется нигде в скрипте — и так и остался незагруженным.

Уже сейчас OpenIDE позволяет разрабатывать проекты на Java, Spring, Python, Go, PHP, JavaScript и TypeScript! А полноценный DB-клиент, поддержка Docker и 300+ плагинов доступны абсолютно бесплатно в маркетплейсе. Пробуйте российскую IDE в деле и подписывайтесь на нас в Telegram или Max, чтобы не пропустить свежие обновления и полезные материалы.