В этом Предложении по улучшению Python (Python Enhancement Proposal, PEP) синтаксис ленивого импорта вводится как явная языковая функция:

lazy import json
lazy from json import dumps

Ленивый импорт откладывает загрузку и выполнение модуля до первого использования импортируемого имени, в отличие от обычного импорта, который сразу загружает и выполняет модуль в точке указания импорта.

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

Это предложение сохраняет полную обратную совместимость: обычные операторы импорта остаются неизменными, а ленивый импорт включается только при явном запросе.

О мотивации

Общепринятое соглашение в коде Python - размещать все импортируемые операции на уровне модуля, обычно в начале файла. Это позволяет избежать повторений, делает зависимости импорта понятными и минимизирует накладные расходы во время выполнения, поскольку оператор импорта вычисляется только один раз для каждого модуля.

Основным недостатком такого подхода является то, что импорт первого модуля для выполнения Python («главного» модуля) часто запускает немедленный каскад импортов и, как ни странно, загружает множество зависимостей, которые могут никогда не понадобиться. Этот эффект особенно дорого обходится для инструментов командной строки с несколькими подкомандами, где даже запуск команды с опцией --help может загрузить десятки ненужных модулей и занять несколько секунд. Этот простой пример демонстрирует, что нужно загрузить только для того, чтобы получить пользователю полезную обратную связь о том, как вообще запустить программу. Неэффективно, но пользователь снова несет эти накладные расходы, когда определяет нужную команду и вызывает программу «по-настоящему».

Довольно распространенный способ отложить импорт - это перенести импорт в функции (встроенный импорт), но эта практика требует больше усилий для реализации и поддержки и может быть сведена на нет одним случайным импортом верхнего уровня. Кроме того, он скрывает полный набор зависимостей модуля. Анализ стандартной библиотеки Python показывает, что примерно 17% всех импортов вне тестов (почти 3500 импортов в 730 файлах) уже размещены внутри функций или методов специально для отсрочки их выполнения. Это показывает, что разработчики уже вручную реализуют ленивый импорт в коде, чувствительном к производительности, но это требует разброса импортов по всей кодовой базе и затрудняет понимание всего графика зависимостей с первого взгляда.

Стандартная библиотека предоставляет класс LazyLoader для решения некоторых из этих проблем неэффективности. Он позволяет импорту на уровне модуля работать практически так же, как встроенный импорт. Многие научные библиотеки Python используют аналогичный шаблон, формализованный в SPEC 1. Существует также сторонний пакет lazy_loader, ещё одна реализация ленивого импорта. Импорт, используемый исключительно для статической проверки типов, является ещё одним источником потенциально ненужного импорта, и существуют аналогичные разрозненные подходы к минимизации накладных расходов. Различные подходы, используемые здесь для отсрочки или удаления жадных импортов, не охватывают все потенциальные варианты использования общего механизма ленивого импорта. Чёткого стандарта нет, и существует ряд недостатков, включая накладные расходы времени выполнения в неожиданных местах или ухудшение самоанализа во время выполнения.

О новом решении

В основе принятого предложения лежат ясность, предсказуемость и простота внедрения. Каждое решение было принято с целью гарантировать, что ленивый импорт обеспечит ощутимые преимущества без внесения излишней сложности в язык или его среду выполнения.

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

Решение о введении нового ключевого слова lazy отражает необходимость явного синтаксиса. Семантика ленивого импорта отличается от семантики обычного импорта: ошибки и побочные эффекты возникают при первом использовании, а не в операторе импорта. Это семантическое различие делает критически важным, чтобы ленивость была видна непосредственно в месте импорта, а не скрывалась в глобальной конфигурации или удалённых объявлениях на уровне модуля. Ключевое слово lazy обеспечивает локальное понимание поведения импорта, избавляя от необходимости поиска в других местах кода, чтобы понять, отложен ли импорт. Остальная семантика импорта остаётся неизменной: используются те же механизмы импорта, поиска модулей и загрузки.

Другое важное решение - представлять ленивый импорт с помощью прокси-объектов в пространстве имён модуля, а не путём изменения поиска по словарю. Ранее были проведены эксперименты с встраиванием. Однако это размывало абстракции и создавало риск влияния на несвязанные части среды выполнения. Словарь - фундаментальная структура данных в Python - буквально каждый объект построен на основе словарей, - и добавление хуков к словарям помешало бы критическим оптимизациям и усложнило бы всю среду выполнения. Подход с прокси проще: он ведёт себя как плейсхолдер до первого использования, после чего разрешает импорт и перепривязывает имя. После этого привязка неотличима от обычного импорта. Это упрощает объяснение механизма и сохраняет остальную часть интерпретатора неизменной.

Совместимость для авторов библиотек также была ключевым вопросом. Многим разработчикам нужен путь миграции, который позволит им одновременно поддерживать как новые, так и старые версии Python. По этой причине предложение включает глобальную переменную lazy_modules в качестве переходного механизма. Модуль может объявить, какие импорты следует рассматривать как ленивые (перечислив имена модулей в виде строк), и в Python 3.15 или более поздних версиях эти импорты автоматически станут ленивыми, как если бы они были импортированы с ключевым словом lazy. В более ранних версиях это объявление игнорируется, и импорты остаются активными. Это даёт авторам практический мостик, пока они не смогут полагаться на ключевое слово как на канонический синтаксис.

Ничего не меняется, если разработчик явно не укажет lazy в своем коде, поэтому внедрение нового синтаксиса может начаться всего с нескольких импортов в областях, чувствительных к производительности. Это отражает опыт постепенного ввода новых фич в Python. Примечательно, что внедрение также может быть выполнено «извне внутрь», что позволяет авторам CLI внедрять ленивый импорт и ускорять работу пользовательских инструментов, не требуя внесения изменений в каждую библиотеку, которую может использовать инструмент.

Сроки внедрения

Новый механизм Python будет внедрен в версии 3.15, то есть в октябре 2026 года.