MidТеория2 min

Что нового в Python 3.14

Свободная многопоточность, шаблонные строки, отложенные аннотации, множественные интерпретаторы и другие изменения релиза 3.14

Python 3.14 вышел как финальный релиз в октябре 2025 года и на момент написания статьи (май 2026) развивается в линейке патч-версий 3.14.x. Это один из самых заметных релизов за последние годы: он официально закрепляет режим без глобальной блокировки интерпретатора, добавляет новый тип строковых литералов и меняет поведение аннотаций типов. Ниже разберём ключевые новшества с примерами.

Свободная многопоточность (free-threading, PEP 779)

Главное изменение релиза — официальная поддержка сборки без GIL (Global Interpreter Lock — глобальная блокировка интерпретатора). Раньше GIL не позволял нескольким потокам Python одновременно исполнять байт-код, из-за чего CPU-bound (нагружающий процессор) код не ускорялся при добавлении потоков. Экспериментальный режим появился ещё в 3.13 (PEP 703), а в 3.14 он переведён из экспериментального в официально поддерживаемый (supported — поддерживаемый) статус.

Такая сборка распространяется отдельно — её называют free-threaded build (сборка со свободной многопоточностью). Проверить, отключён ли GIL, можно так:

import sys

# sys._is_gil_enabled() returns False on free-threaded build
if hasattr(sys, "_is_gil_enabled"):
    print("GIL enabled:", sys._is_gil_enabled())

Теперь реальная параллельность достигается обычными потоками:

from concurrent.futures import ThreadPoolExecutor

def heavy(n: int) -> int:
    total = 0
    for i in range(n):
        total += i * i
    return total

# On a free-threaded build these run truly in parallel across cores
with ThreadPoolExecutor(max_workers=4) as pool:
    results = list(pool.map(heavy, [10_000_000] * 4))

print(sum(results))

Важно: за многопоточность приходится платить. На однопоточном коде free-threaded сборка медленнее обычной примерно на 5-10% (depending on platform — в зависимости от платформы и компилятора C). Поэтому свободную многопоточность стоит выбирать осознанно — когда задача действительно CPU-bound и параллелизуема.

Шаблонные строки (t-strings, PEP 750)

Появился новый вид строковых литералов — template strings (шаблонные строки), записываемые с префиксом t. В отличие от f-string (форматированной строки), которая сразу вычисляет выражения и склеивает результат в готовую строку str, t-string возвращает объект Template, дающий доступ к подставляемым значениям до финальной сборки строки.

name = "Мир"

# f-string evaluates immediately into a str
f_value = f"Привет, {name}!"      # "Привет, Мир!" (type str)

# t-string returns a Template object instead of a str
t_value = t"Привет, {name}!"      # Template object

У объекта Template есть поля strings (статические куски текста) и interpolations (подстановки), что позволяет обработать каждое значение отдельно. Это основа для безопасных шаблонов: например, экранирования HTML или защиты от SQL-инъекций.

from string.templatelib import Template, Interpolation

def render_safe(template: Template) -> str:
    parts: list[str] = []
    for item in template:
        if isinstance(item, Interpolation):
            # We control how interpolated values are rendered (e.g. escaping)
            parts.append(str(item.value).replace("<", "&lt;"))
        else:
            parts.append(item)
    return "".join(parts)

user_input = "<script>"
print(render_safe(t"Комментарий: {user_input}"))
# Комментарий: &lt;script>

Ключевая идея: t-string сама по себе ничего не форматирует. Логику преобразования значений пишет разработчик (или библиотека), что делает шаблоны безопаснее, чем наивная конкатенация (concatenation — склеивание строк).

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

Аннотации типов теперь вычисляются лениво (lazily — отложенно), а не в момент определения функции или класса. Раньше для ссылок на ещё не объявленные типы приходилось писать строковые аннотации или добавлять from __future__ import annotations. Теперь аннотации хранятся в специальной функции-обёртке и вычисляются только при обращении к ним.

class Node:
    # Reference to Node works without quotes or __future__ import
    def link(self, other: Node) -> Node:
        self.next = other
        return other

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

import annotationlib

ann = annotationlib.get_annotations(Node.link)
print(ann)  # {'other': <class '__main__.Node'>, 'return': <class '__main__.Node'>}

Практическая польза: исчезает большинство ошибок с forward reference (опережающая ссылка — ссылка на тип, объявленный ниже по коду), а интроспекция типов становится надёжнее.

Множественные интерпретаторы (PEP 734)

Добавлен модуль стандартной библиотеки concurrent.interpreters — высокоуровневый интерфейс к нескольким субинтерпретаторам (subinterpreters — изолированные интерпретаторы внутри одного процесса). Каждый из них имеет собственное состояние и собственный GIL, поэтому они тоже дают параллельность, но через изоляцию, а не через общую память.

from concurrent import interpreters

interp = interpreters.create()
interp.exec("print('Привет из другого интерпретатора')")
interp.close()

Это альтернатива многопроцессности (multiprocessing): субинтерпретаторы легче процессов, но изолированнее потоков. Подходит, когда нужна параллельность с минимальным разделяемым состоянием (shared state — общее состояние).

Прочие изменения

Несколько менее крупных, но полезных нововведений:

  • PEP 758 — except и except* можно писать без скобок при перечислении нескольких типов исключений: except ValueError, TypeError: (catch multiple exceptions — перехват нескольких исключений).
  • PEP 765 — предупреждение об управляющих конструкциях в блоке finally (например, return или break внутри finally, что молча гасит исключения).
  • PEP 784 — поддержка формата сжатия Zstandard через новый модуль compression.zstd в стандартной библиотеке.
  • Улучшенные сообщения об ошибках (improved error messages) — интерпретатор точнее подсказывает причину ошибки и опечатки в именах.
  • Инкрементальная сборка мусора (incremental garbage collection) — снижает паузы при работе сборщика мусора на больших объёмах объектов.
# PEP 758: brackets around multiple exception types are now optional
try:
    risky()
except ValueError, KeyError:
    print("обработали обе ошибки")

Итог

Python 3.14 — релиз про производительность и масштабирование: free-threading и множественные интерпретаторы открывают путь к настоящей параллельности, t-strings делают шаблонизацию безопасной, а PEP 649 убирает давнюю боль с аннотациями. Для большинства проектов переход на 3.14 безболезненный, а новые возможности можно внедрять постепенно.

Проверь себя

Что меняет PEP 779 в Python 3.14?

Чем t-string (PEP 750) отличается от f-string?

Какую проблему решает отложенное вычисление аннотаций (PEP 649)?

Какой модуль стандартной библиотеки появился по PEP 734 для работы с несколькими интерпретаторами?