Статьи

Python 3.14: что нового ждет разработчиков?

Синтаксис Python

Эта статья — мой разбор официальных заметок о релизе. Для тех, кто любит копаться в первоисточниках и не боится простыней текста на английском — вот ссылка на официальный changelog.

Выход Python 3.14 запланирован на октябрь 2025. Python активно качает мускулы в сторону производительности и настоящего параллелизма.

Давайте разберемся, что же такого важного планируют в этой версии.

Главное событие: Производительность и конец эпохи GIL?

C версии 3.14 удаление GIL стало официальной стратегией. Несколько ключевых PEP направлены именно на то, чтобы Python мог эффективно работать на многоядерных процессорах.

PEP 779: Free-threaded Python — это официально

Самая громкая новость: сборка Python без GIL (free-threaded) теперь официально поддерживается. Это больше не экспериментальная фича. Что это значит на практике?

  • Начало конца GIL: Мы вступаем в фазу, где free-threaded сборка — это поддерживаемая, но все еще опциональная возможность. Переход к ней как к сборке по умолчанию — вопрос будущего, но вектор движения задан четко.
  • Цена свободы: За настоящий параллелизм приходится платить. В однопоточных сценариях производительность free-threaded сборки пока что на 5-10% ниже, чем у классической сборки с GIL. Но это та цена, которую многие готовы заплатить за возможность распараллеливать задачи без костылей в виде multiprocessing.

Разработчики ядра уверены в выбранном пути, а сообщество активно работает над адаптацией библиотек.

PEP 734: Множественные интерпретаторы в стандартной библиотеке

Еще один мощный удар по ограничениям GIL. Возможность запускать несколько изолированных интерпретаторов в одном процессе существует в C-API уже лет 20, но только сейчас она стала доступна напрямую из Python через новый модуль concurrent.interpreters.

[!NOTE] Думайте об этом так: изоляция как у multiprocessing, но эффективность как у threading.

Это открывает дорогу к двум вещам:

  1. Настоящий многоядерный параллелизм: Интерпретаторы достаточно изолированы, чтобы работать параллельно, не упираясь в один GIL.
  2. Новые модели конкурентности: Можно реализовывать подходы вроде модели акторов или CSP, популярные в Go или Erlang, где потоки общаются через передачу данных, а не через общую память.

Конечно, есть и ограничения:

  • Запуск интерпретаторов пока не оптимизирован.
  • Потребление памяти выше необходимого.
  • Мало опций для "честного" шаринга данных между интерпретаторами (кроме memoryview).
  • Многие сторонние C-расширения еще не готовы к такому режиму.

Тем не менее, для CPU-емких задач это революционная возможность. В комплекте идет и новый concurrent.futures.InterpreterPoolExecutor.

Новый интерпретатор с хвостовыми вызовами

В CPython добавили новый тип внутреннего интерпретатора. Вместо гигантского switch-case для опкодов он использует хвостовые вызовы между небольшими C-функциями. На новых компиляторах (пока что Clang 19+) это дает заметный прирост производительности — в среднем 3-5% на стандартных бенчмарках.

[!WARNING] Это не оптимизация хвостовых вызовов в вашем Python-коде (рекурсия по-прежнему не оптимизируется). Это внутреннее изменение CPython.

Экспериментальный JIT-компилятор

Официальные сборки для macOS и Windows теперь включают экспериментальный JIT-компилятор. Включается он переменной окружения PYTHON_JIT=1. Пока это очень ранняя стадия, и прирост производительности нестабилен (от -10% до +20%), но это явный знак, куда движется CPython.

Ключевые изменения в языке и синтаксисе

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

PEP 750: Template Strings (t-строки)

Это обобщение f-строк. Если f-строка сразу вычисляется в str, то t-строка, с префиксом t, вычисляется в специальный объект string.templatelib.Template.

from string.templatelib import Template, Interpolation

name = "World"
template: Template = t"Hello {name}"

Зачем это нужно? Этот Template объект хранит структуру строки: где статические части, а где подстановки. Это позволяет писать "умные" обработчики шаблонов. Самый очевидный пример — безопасная генерация HTML.

# Представим, что у нас есть такая функция
def html(template: Template) -> str:
    # ... логика экранирования ...
    ...

evil = "<script>alert('evil')</script>"
template = t"<p>{evil}</p>"

# html() видит, что evil - это подстановка, и экранирует ее
assert html(template) == "<p>&lt;script&gt;alert('evil')&lt;/script&gt;</p>"

Сравните с f-строкой, которая бы просто подставила вредоносный код. T-строки открывают двери для безопасных SQL-запросов, генерации CSS, легковесных DSL и многого другого прямо "из коробки".

PEP 649 и 749: Отложенное вычисление аннотаций

Аннотации типов теперь не вычисляются в момент определения функции или класса. Они сохраняются в специальном виде и вычисляются только по требованию (например, при вызове get_annotations).

Что это дает?

  1. Производительность: Определение функций с аннотациями становится быстрее.
  2. Больше не нужны кавычки для forward-ссылок: Наконец-то можно писать def func(arg: Node) -> Node: без оборачивания Node в строки, даже если класс Node определен ниже.
  3. Конец from __future__ import annotations: Этот импорт теперь считается устаревшим и в будущем будет удален.

Для интроспекции аннотаций появился новый модуль annotationlib с функцией get_annotations(), которая позволяет получать аннотации в разных форматах (вычисленные значения, строковые представления и т.д.).

PEP 758: except и except* без скобок

Небольшое, но приятное улучшение. Если вы ловите несколько исключений и не используете as, скобки теперь можно опустить.

# Раньше было обязательно
try:
    ...
except (TimeoutError, ConnectionRefusedError):
    ...

# Теперь можно так
try:
    ...
except TimeoutError, ConnectionRefusedError:
    ...

Это работает и для except*.

Новые инструменты и модули

PEP 784: Zstandard в стандартной библиотеке

В Python добавили поддержку высокоэффективного и быстрого алгоритма сжатия Zstandard. Появился новый пакет compression, который объединяет модули для работы со сжатием, и внутри него — compression.zstd.

from compression import zstd
import math

data = str(math.pi).encode() * 20
compressed = zstd.compress(data)

Поддержка zstd также добавлена в tarfile, zipfile и shutil.

PEP 768: Безопасный внешний отладчик и удаленный PDB

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

Практическое применение, которое оценят многие: теперь pdb можно подключить к работающему процессу по его PID.

python -m pdb -p 12345

Это невероятно мощный инструмент для отладки "зависших" или ведущих себя странно приложений в продакшене или на стейджинге.

Улучшенные сообщения об ошибках

Интерпретатор стал еще умнее и теперь подсказывает при опечатках в ключевых словах.

whille True:
    pass
# SyntaxError: invalid syntax. Did you mean 'while'?

async def foo():
    awaid fetch_data()
# SyntaxError: invalid syntax. Did you mean 'await'?

Другие заметные изменения

  • map(strict=True): Встроенная функция map() получила флаг strict (как у zip()), который проверяет, что все итерируемые объекты имеют одинаковую длину.
  • Новые методы pathlib.Path: Добавлены методы copy(), copy_into(), move() и move_into() для рекурсивного копирования и перемещения файлов/директорий.
  • UUID v6, v7, v8: Добавлена поддержка новых версий UUID, как указано в RFC 9562.
  • Подсветка синтаксиса в REPL: Интерактивная консоль Python теперь по умолчанию подсвечивает синтаксис.
  • os.path.realpath(strict=os.path.ALLOW_MISSING): Новый режим для realpath, который разрешает отсутствующие компоненты в пути, но все равно разрешает симлинки.

Что пора перестать использовать: Депрекейты и удаления

  • from __future__ import annotations: Официально устарел.
  • asyncio полиси: Вся система политик (get_event_loop_policy, set_event_loop_policy) устарела в пользу asyncio.run(loop_factory=...).
  • asyncio.get_event_loop(): Неявное создание цикла событий удалено. Если цикл не запущен, вызов этой функции теперь вызовет RuntimeError.
  • Удалены старые узлы ast: ast.Num, ast.Str, ast.Bytes и ast.NameConstant окончательно удалены. Используйте ast.Constant. Если вы писали свои визиторы AST, вам придется их обновить.
  • codecs.open(): Устарел. Используйте встроенный open().

Выводы

Язык делает решительный шаг в мир высокопроизводительных вычислений и настоящего параллелизма. Официальная поддержка free-threaded режима, множественные интерпретаторы и экспериментальный JIT — все это кирпичики в фундаменте будущего Python, где он сможет на равных конкурировать с другими языками в CPU-bound задачах.