Лучшие новые возможности Python 3.15: lazy imports, frozendict, sentinel() и ускоренный JIT
Главные новинки Python 3.15, который уже доступен в бета-версии, — это lazy imports, более быстрый JIT, улучшенные сообщения об ошибках и более умное профилирование.
Первая полноценная бета-версия Python 3.15 уже вышла, и это один из самых насыщенных релизов Python за долгое время. Ниже — обзор самых крупных, смелых и важных нововведений, изменений и исправлений.
Lazy imports
Давно ожидаемая функция lazy imports позволяет обрабатывать импорты только в тот момент, когда программа действительно начинает их использовать. Для модулей с медленным импортом, которые заметно увеличивают время запуска программы, теперь можно легко перенести эту стоимость на момент, когда код этого модуля действительно будет выполнен.
Использовать lazy imports можно явно — через новый синтаксис ленивого импорта, а можно заставить обычные импорты работать лениво программно или через переменную окружения. Это упрощает внедрение функции в существующий код без масштабной переработки. И что особенно важно, у ленивых импортов нет побочных эффектов: в остальном они ведут себя так же, как и обычно.
The frozendict built-in type
Python редко добавляет новый тип данных, но это как раз давно обсуждаемое и давно желаемое пополнение — frozen dictionary. Объект frozendict ведет себя как обычный словарь, но он неизменяемый (нельзя добавлять, удалять или изменять элементы) и хешируемый (например, его можно использовать как ключ в другом словаре).
The sentinel() built-in type
Еще одно новшество языка предназначено для замены распространенного и проблемного шаблона Python: создания уникального объекта sentinel вместо None в тех случаях, когда None может быть допустимым значением, — обычно через object(). Новый синтаксис sentinel("NAME") создает уникальные объекты, которые сравниваются только сами с собой через оператор is. Такие объекты корректно проверяются типизатором, а их представление в выводе информативнее, чем у случайного дескриптора объекта.
A statistical sampling profiler
Давно существующий модуль cProfile профилирует код Python детерминированно — то есть отслеживает и записывает каждый вызов. Это дает высокую точность, но означает и то, что программа под cProfile работает заметно медленнее обычного. Новый модуль профилирования в Python 3.15, profiling.sampling, использует статистическую выборку, чтобы собирать полезные сведения о производительности с гораздо меньшим влиянием на скорость программы. Существующий профилировщик cProfile по-прежнему доступен — он никуда не исчезает, — но теперь имеет новое альтернативное имя profiling.tracing.
An upgraded JIT
Встроенный в CPython компилятор just-in-time (JIT) дебютировал в Python 3.13. Его долгосрочная цель — ускорять Python-программы без изменений в коде, примерно так же, как это делает альтернативная реализация Python, PyPy. При этом не нужно переходить на совсем другой интерпретатор со своими ограничениями.
Первые несколько ревизий JIT не обещали и не давали большого прироста скорости, потому что тогда основное внимание было сосредоточено на закладке фундамента для будущих улучшений. Но в Python 3.15 JIT уже показывает геометрическое среднее ускорение на 8%–13% по сравнению со стандартным CPython, в зависимости от платформы и нагрузки. Крупнейшие изменения включают новый tracing front end, который открывает путь к ускорениям для большего числа типов кода; использование register allocation для более быстрой и экономной работы с памятью; более качественный машинный код, который генерирует JIT; а также дополнительные оптимизации, например устранение счетчиков ссылок для некоторых классов объектов.
Better error messages
Сообщения об ошибках в Python в последних версиях становятся все точнее, подробнее и полезнее, и Python 3.15 продолжает эту работу. Основные улучшения:
- Подсказки для отсутствующих имен («
xhas no attribute ‘y‘. Did you mean ‘xyz‘?») теперь учитывают не только сам объект, но и его члены. - Подсказки теперь работают и для проверки удаления атрибутов, а не только для обращения к ним.
- Если интерпретатор не может предложить метод по нечеткому совпадению имени через расстояние Левенштейна, он обращается к списку имен, которые обычно используются в других языках для таких методов. Например, если вы попытаетесь использовать
list.push()— метод JavaScript, — интерпретатор предложит.append(), правильный метод для списков Python.
Type system improvements
Класс TypedDict, который позволяет создавать словари с заранее заданными ключами и аннотациями типов для ключей и значений, получил поддержку двух новых аргументов в описании. Аргумент closed позволяет указать, можно ли во время выполнения использовать только перечисленные ключи. Аргумент extra_items позволяет разрешить дополнительные ключи во время выполнения, но только если их значения имеют указанный тип.
Определение типа TypeForm позволяет представлять значение, которое получается после вычисления выражения типа. Благодаря этому аннотации типов можно использовать там, где сам тип применяется как значение, — например, в вариантах операций вроде typing.cast или даже isinstance, а также как часть работы стороннего инструмента проверки типов.
Unpacking in comprehensions
Это еще одна давно ожидаемая возможность. Если вам нужно было полностью распаковать или «сплющить» вложенный объект с помощью comprehension, раньше приходилось использовать функцию вроде itertools.chain() или писать вложенное comprehension с неудобным синтаксисом:
x = [[1,2,3],[4,5],[6]]
y = [a for b in x for a in b]
>>> [1, 2, 3, 4, 5, 6] # y
Распаковка в comprehension с использованием оператора звездочки позволяет убрать лишний шаг:
x = [[1,2,3],[4,5],[6]]
y = [*a for a in x]
>>> [1, 2, 3, 4, 5, 6] # y
Распаковка с ** тоже работает, например для выравнивания и объединения словарей:
dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
y = {**d for d in dicts}
>>> {'a': 3, 'b': 2}
Наконец, такую распаковку можно использовать и для генераторных выражений:
(*x for x in ["ab","cd","ef"])
Выражение выше создает генератор, который выдает:
['a', 'b', 'c', 'd', 'e', 'f']
Reverting the incremental garbage collector
Наконец, Python 3.15 делает важный разворот. В Python 3.14 была реализована крупная смена системы сборки мусора — incremental garbage collector, призванный сократить время, когда программа останавливается для сборки мусора. Однако многие пользователи сообщали, что новый сборщик мусора увеличивает потребление памяти процессом, иногда весьма заметно. Поэтому Python 3.15 вернется к старому generational garbage collector, который использовался в Python 3.13 и более ранних версиях. Incremental collector может вернуться в будущей версии, но только после дополнительной доработки, которая не позволит этой проблеме повториться.
Материал — перевод статьи с английского.
Оригинал: The best new features in Python 3.15