Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11

Что нового в Python 3.14: разбираем главные изменения

Обзор изменений Python 3.14: новые возможности синтаксиса и улучшения производительности

2К открытий5К показов
Что нового в Python 3.14: разбираем главные изменения

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

Вам больше не придется ставить скобки при перехвате исключений, появились строки-шаблоны для безопасного форматирования и множественные улучшения многопоточности. Разберём ключевые нововведения на конкретных примерах кода — от обработки ошибок до параллельных вычислений.Материал будет полезен как опытным разработчикам, так и тем, кто только начинает погружаться в мир Python. .

Улучшенный синтаксис и новые возможности

Python 3.14 вносит несколько изменений в синтаксис языка. Они затронут обработку исключений, работу со строками и аннотациями.

Обработка исключений без скобок

Раньше при перечислении нескольких исключений в блоке except нужно было ставить скобки. Теперь это правило смягчили. Скобки можно не указывать, если вы не используете ключевое слово as. Это мелочь, но она делает код аккуратнее.

Вот как выглядело раньше:

			python
try:
 risky_operation()
 except (ValueError, TypeError, IndexError):
  handle_error()

		

Теперь можно писать так:

			python
try:
    risky_operation()
except ValueError, TypeError, IndexError:
    handle_error()

		

Но если нужно поймать исключение в переменную, скобки все равно требуются:

			python
try:
    risky_operation()
except (ValueError, TypeError, IndexError) as e:
    handle_error(e)
		

Это изменение описано в PEP 758. Python Enhancement Proposal — официальный документ с предложениями по улучшению Python, в котором описаны новые функции, процессы или среды разработки языка.

Строки-шаблоны для безопасной обработки

В Python 3.14 появились строки-шаблоны (template strings). Их отмечают префиксом t вместо привычного f. Такие строки не вычисляются сразу в строковый объект. Вместо этого они возвращают специальный объект Template, который можно обработать особым образом.

Пример создания шаблона:

			python
name = "Алексей"
template = t"Привет, {name}!"
		

Такой шаблон можно разбирать на части. Это полезно для безопасной вставки значений, например, в HTML или SQL-запросы. Вы сами контролируете процесс подстановки и можете экранировать опасные символы.

Вот пример функции, которая корректно обрабатывает HTML:

			python
from string.templatelib import Template, Interpolation
import html
def safe_html(template: Template) -> str:
    parts = []
    for item in template:
        if isinstance(item, Interpolation):
            # Экранируем HTML-символы с помощью стандартной функции
            safe_value = html.escape(str(item.value))
            parts.append(safe_value)
        else:
            parts.append(item)
    return "".join(parts)
user_input = "<script>alert('test')</script>"
result = safe_html(t"<div>{user_input}</div>")
print(result)  # Выведет: <div><script>alert('test')</script></div>

		

Это основано на PEP 750.

Ленивые аннотации типов

Аннотации типов в Python 3.14 перешли на новую модель вычисления. Раньше они вычислялись сразу при создании объектов, что вызывало проблемы с резоловингом имен в рантайме. Теперь используется механизм отложенного вычисления через дескриптор __annotations__ и атрибут __annotate__.

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

Вот как выглядела типичная проблема раньше:

			python
class MyClass:
    @classmethod
    def build(cls) -> MyClass:  # Ошибка: NameError - MyClass еще не определен
        return MyClass()
		

Теперь этот код работает корректно. При компиляции аннотация -> MyClass сохраняется как строка. Когда вы обращаетесь к MyClass.build.__annotations__, дескриптор запускает механизм вычисления и возвращает готовый тип.

Новая логика компилятора разделяет процесс на два этапа:

  1. Генерация функции `__annotate__` из AST во время работы компилятора
  2. При вызове дескриптора `.__annotations__` теперь будет вызван `.__annotate__(format=annotationlib.Format.VALUE)`

Пример работы нового механизма:

			python
class DataClass:
    def process(self) -> ResultClass:  # Теперь всегда пишем без кавычек
        pass

class ResultClass:
    @classmethod
    def create(cls) -> DataClass:  # Работает без кавычек
        return DataClass()

# Аннотации вычисляются при первом обращении
print(DataClass.process.__annotations__)  # Выведет: {'return': <class '__main__.ResultClass'>}

		

Это изменение основано на PEP 649 и делает работу с аннотациями более интуитивной и надёжной. Более того, `from _future_ import annotations` теперь не нужен для корректной работы — это признано не самым удачным решением.

Для работы с аннотациями добавили модуль annotationlib. Он позволяет получать аннотации в разных форматах:

			python
from annotationlib import get_annotations, Format

def example_func(param: UndefinedType) -> None:
    pass

# Получить аннотации в виде строк
print(get_annotations(example_func, format=Format.STRING))
# Выведет: {'param': 'UndefinedType', 'return': 'None'}

# Попытка получить вычисленные значения вызовет ошибку, если тип не определен
# get_annotations(example_func, format=Format.FORWARDREF)  # Вызовет NameError

		

Эту возможность внесли по PEP 649 и PEP 749.

Изменения в стандартной библиотеке

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

Модуль compression.zstd для быстрого сжатия

В стандартной библиотеке Python 3.14 появился модуль для работы с алгоритмом сжатия Zstandard (zstd). Эта технология изначально разрабатывалась в Facebook* и уже несколько лет доступна как сторонняя библиотека zstandard. Теперь она интегрирована в стандартную поставку Python по PEP 784.

*Компания Meta признана на территории РФ экстремистской и запрещена.

Zstandard демонстрирует лучшую эффективность и скорость по сравнению с классическим zlib. Алгоритм особенно хорошо показывает себя на современных многоядерных процессорах, поддерживая распараллеливание операций сжатия.

Основные преимущества zstd:

  • высокая скорость сжатия и распаковки;
  • хорошая степень сжатия, сравнимая с zlib;
  • поддержка словарей для улучшенного сжатия текстовых данных;
  • возможность настройки уровня сжатия от 1 до 22.

Пример использования:

			python
from compression import zstd

data = b"Это тестовые данные, которые мы хотим сжать. " * 100

compressed = zstd.compress(data)
print(f"Исходный размер: {len(data)}, сжатый: {len(compressed)}")

decompressed = zstd.decompress(compressed)
assert data == decompressed

		

Для тех, кто работал с внешней библиотекой zstandard, интерфейс будет знакóм. Модуль сохраняет совместимость с API оригинальной реализации, что упрощает переход на стандартную версию.

Новые методы для Path в pathlib

Класс Path в модуле pathlib получил методы для копирования и перемещения файлов. Раньше для этих операций приходилось использовать функции из shutil или писать собственные реализации. Теперь работа с файлами стала более удобной и логичной.

Пример копирования файла с проверкой сохранности исходного файла:

			python
from pathlib import Path

source = Path("исходный_файл.txt")
destination = Path("целевая_папка") / "копия_файла.txt"

# Создаем исходный файл для демонстрации
source.write_text("Содержимое файла")

# Копируем файл
source.copy(destination)

# Проверяем, что файл скопирован
print(destination.read_text())  # Выведет: Содержимое файла

# Исходный файл остается на месте и не изменяется
print(source.read_text())  # Выведет: Содержимое файла
print(source.exists())  # Выведет: True

		

Метод copy() создает копию файла, оставляя оригинал без изменений. Это важно понимать при работе с критически важными данными.

Пример перемещения файла:

			python
from pathlib import Path

source = Path("старое_место.txt")
target = Path("новая_папка") / "новое_имя.txt"

# Создаем исходный файл и целевую папку
source.write_text("Данные файла")
target.parent.mkdir(exist_ok=True)

# Перемещаем файл
source.move(target)

# Проверяем, что файл перемещен
print(target.exists())  # Выведет: True
print(source.exists())  # Выведет: False

		

Поддержка UUID версий 6-8

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

UUIDv6 сохраняет временную информацию как UUIDv1, но использует более удобный порядок байт. Это позволяет эффективно индексировать временные метки в базах данных без дополнительных преобразований. Идеален для систем, где важна хронологическая сортировка идентификаторов.

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

UUIDv8 предоставляет гибкость для кастомных реализаций. Разработчики могут определять собственную структуру UUID под специфические требования проектов.

Пример генерации новых UUID:

			python
import uuid

# Для временных рядов и логов
uuid6 = uuid.uuid6()

# Для веб-приложений и API
uuid7 = uuid.uuid7()

# Для экспериментальных и кастомных решений  
uuid8 = uuid.uuid8()

		

Выбор версии зависит от конкретных требований к сортировке, безопасности и структуре идентификаторов в вашей системе.

Многопоточность и параллелизм

Важное направление эволюции Python — улучшенная поддержка многопоточности и параллельных вычислений. В версии 3.14 этот тренд развивается особенно активно.

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

Запускать несколько интерпретаторов в одном процессе в Python можно давно, но эта функция была доступна только через C-API. Теперь опцию вынесли в стандартную библиотеку в модуль concurrent.interpreters.

Интерпретаторы изолированы друг от друга лучше, чем потоки. Каждый интерпретатор имеет собственное состояние и, по умолчанию, собственный GIL. Это настраивается — через C-API можно создать интерпретаторы с общим GIL или полностью независимые.

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

Пример запуска кода в отдельном интерпретаторе:

			python
>>> from concurrent.interpreters import create
>>> interp = create()
>>> def add(x: int, y: int) -> int:
...     print(x, y)
...     return x + y
...     
>>> interp.call(add, 2, 3)
2 3
5
>>> interp.close()

		

Система даёт разработчикам гибкость в выборе модели параллелизма в зависимости от конкретных требований приложения. Модуль concurrent.futures предоставляет высокоуровневый интерфейс для асинхронного выполнения, а interpreters позволяет работать с множественными интерпретаторами Python, что особенно полезно для изоляции задач и эффективного использования ресурсов.

Больше подробностей — в этом видео.

Официальная поддержка свободной многопоточности

Свободная многопоточность (free-threading) перестала быть экспериментальной. Теперь это официально поддерживаемая опция сборки Python. В таком режиме интерпретатор не использует GIL, что позволяет потокам работать действительно параллельно.

Это особенно полезно для задач, связанных с интенсивными вычислениями. Например, для научных расчетов или обработки больших данных. Также есть преимущества для сетевых операций — можно обрабатывать множество соединений одновременно без блокировок GIL.

Однако не все сторонние библиотеки совместимы с этим режимом. Многие расширения разрабатывались с учетом существования GIL и могут требовать доработки для безопасной работы в многопоточной среде без глобальной блокировки.

Производительность и внутренние улучшения

Каждая новая версия Python приносит оптимизации производительности. В 3.14 эти улучшения особенно заметны.

Новый интерпретатор с промежуточными вызовами

Tail-Calling Interpreter — это не оптимизация хвостовой рекурсии в языке Python для программистов, а внутренний метод диспетчеризации байт-кода в самом интерпретаторе CPython. Он призван заменить ранее использовавшиеся подходы (огромный switch-оператор или вычисляемые goto) для более эффективного перехода между обработчиками отдельных инструкций байт-кода.

Вместо одного большого цикла с оператором switch или множественных переходов между метками внутри гигантской функции каждый обработчик инструкции (например, OP_ADD) теперь реализован как небольшая самостоятельная функция на языке C. Завершается такая функция не простым возвратом, а хвостовым вызовом (tail call) следующей функции-обработчика.

Это возможно благодаря специальным атрибутам компилятора:

  • [[clang::musttail]] — гарантирует, что компилятор преобразует вызов в прямой прыжок (jump), а не в классический call с созданием нового стек-фрейма.
  • __attribute__((preserve_none)) (GHC-соглашение о вызовах) — указывает, что функция не должна сохранять значения регистров, что минимизирует накладные расходы при таком стиле диспетчеризации.

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

Подробнее об этом читайте в тг-канале Находки в опенсорсе Никиты Соболева.

Оптимизация счетчиков ссылок

Это изменение основано на реализации «immortal objects» (PEP 683), где некоторые встроенные объекты становятся бессмертными. Их счетчики ссылок перестают изменяться, что уменьшает нагрузку на механизм управления памятью и делает такие объекты полностью иммутабельными на уровне C.

Подробнее об этой оптимизации можно узнать из PEP 683 и обсуждений в рабочих группах по производительности Python.

Инструменты разработчика и отладка

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

Безопасный интерфейс для внешних отладчиков

Добавили безопасный интерфейс (PEP 768) для подключения отладчиков к работающим процессам Python. Раньше отладчики использовали недокументированные возможности, что могло привести к нестабильной работе.

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

Основные компоненты интерфейса:

  • sys.debug_attach() — инициализация отладочной сессии
  • sys.debug_detach() — завершение сессии
  • sys.debug_eval() — выполнение кода в контексте процесса

Пример использования для отладки работающего приложения:

			python
import sys
import threading
import time

# Целевая функция для отладки
def target_function():
    counter = 0
    while True:
        counter += 1
        time.sleep(1)
        print(f"Итерация: {counter}")

# Запускаем фоновый процесс
thread = threading.Thread(target=target_function, daemon=True)
thread.start()

# Даем время на запуск
time.sleep(0.1)

# Подключаемся к процессу для отладки
debug_session = sys.debug_attach()

try:
    # Выполняем код в контексте целевого потока
    result = debug_session.eval("""
        import inspect
        frames = inspect.stack()
        current_frame = frames[0]
        return f"Текущий фрейм: {current_frame.function}, итерация: {counter}"
    """, thread_id=thread.ident)
    
    print(f"Результат отладки: {result}")
finally:
    debug_session.detach()

		

Интерфейс обеспечивает безопасное подключение без остановки процесса. Отладчик получает доступ к стеку вызовов, переменным и состоянию потоков через стандартизированное API.

Предупреждения для return в finally

Блок finally предназначен для очистки ресурсов. Операторы return, break или continue в этом блоке могут привести к неожиданному поведению (ниже рассмотрим пример). Теперь компилятор выдает SyntaxWarning для таких случаев.

Пример проблемного кода:

			python
def problematic_function():
    try:
        return "value from try"
    finally:
        return "value from finally"  # Теперь вызовет SyntaxWarning

result = problematic_function()
print(result)  # Выведет: "value from finally"
		

В нормальной ситуации функция вернула бы значение из блока try. Но из-за return в finally возвращается другое значение. Теперь компилятор предупредит о потенциальной проблеме.

Безопасность и подписи релизов

Изменения затронули и процесс распространения Python. Разработчики отказались от PGP-подписей в пользу более современного решения. Причины апдейта — растущая сложность работы с PGP и сниженная популярность этого способа среди разработчиков.

Переход на Sigstore

Начиная с Python 3.14, релизы больше не подписывают с помощью PGP. Вместо этого используют Sigstore — современный стандарт для подписи, проверки и защиты программного обеспечения. Sigstore — это набор инструментов с открытым исходным кодом, включающий Cosign для подписи контейнеров, Fulcio для управления сертификатами и Rekor для ведения прозрачного журнала.

Новый подход решает ключевые проблемы PGP:

  • Sigstore использует кратковременные сертификаты, привязанные к идентификаторам OIDC (OpenID Connect) — теперь не нужно бесконечно хранить приватные ключи. 
  • Система обеспечивает проверяемую прозрачность через публичный журнал всех операций подписи. Каждая подпись сопровождается временной меткой и информацией о сертификате.

Разработчики могут проверять подписи с помощью инструмента sigstore-python. Пример проверки выглядит так:

			bash
python -m sigstore verify identity \
    --cert-identity "release-manager@python.org" \
    --cert-oidc-issuer "https://accounts.python.org" \
    Python-3.14.0.tgz

		

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

Подготовка к переходу на Python 3.14

Переход на новую версию требует тщательной подготовки. Обратите внимание на ключевые моменты, чтобы избежать проблем.

Проверка совместимости

Некоторые изменения нарушают обратную совместимость. Платформы, кроме macOS и Windows, теперь по умолчанию используют forkserver вместо fork для multiprocessing и ProcessPoolExecutor. Это связано с проблемами стабильности при использовании fork в многопоточных приложениях.

Новый подход может вызывать ошибки NameError или проблемы с pickle. Модули, которые полагаются на унаследованное состояние после fork, потребуют доработки. Проверьте код на совместимость с методом запуска forkserver. Особое внимание уделите работе с глобальными переменными и открытыми ресурсами.

Системные администраторы должны обновить конфигурации развертывания. Новые методы запуска влияют на управление процессами в production-среде.

Обновление инструментов

Новый синтаксис не работает в предыдущих версиях Python. Строки-шаблоны и другие возможности требуют обновить весь инструментарий:

  • Проверьте поддержку Python 3.14 в ваших IDE и редакторах. Обновите линтеры и форматеры кода. MyPy и другие статические анализаторы потребуют новых версий для корректной работы с обновленной системой типов.
  • Интеграционным системам нужна настройка. Обновите конфигурации CI/CD для тестирования на Python 3.14. Убедитесь, что системы сборки поддерживают новую версию.
  • Сторонние библиотеки могут требовать обновления. Проверьте совместимость ключевых зависимостей вашего проекта. Некоторые пакеты могут еще не поддерживать новые возможности Python.
  • Документационные генераторы и инструменты тестирования также нуждаются в проверке. Убедитесь, что вся экосистема разработки готова к переходу.

Итоги

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

Улучшения в многопоточности и параллелизме помогают использовать современное железо. А новые модули стандартной библиотеки избавляют от необходимости искать сторонние решения.

Официальный релиз запланирован на 7 октября 2025 года. У вас есть время подготовиться к переходу. Проверьте свои проекты на совместимость и познакомьтесь с новыми возможностями.

Python остается языком, который развивается с учетом потребностей разработчиков. Версия 3.14 — очередной шаг в этом направлении.

Следите за новыми постами
Следите за новыми постами по любимым темам
2К открытий5К показов