Вкратце:
Сокращённый синтаксис для передачи именованных аргументов при вызове отклонён.
Производительность Python 3.14 оказалась не такой уж впечатляющей.
Депрекации в setuptools ломают проекты.
Новый формат lock-файла для Python — готов.
Dependabot теперь поддерживает uv.
PEP 736 отклонён
PEP 736, предлагающий сокращённый синтаксис для передачи именованных аргументов при вызове функции, был отклонён.
Предложение вводило синтаксический сахар для случаев, когда имя переменной и имя аргумента совпадают.
Например, такой вызов:
sign_in(username=username, password=password, otp_code=get_otp())
можно было бы сократить до:
sign_in(username=, password=, otp_code=get_otp())
Это избавляло бы от утомительного повторения и выделяло те места, где значения действительно различаются.
В JavaScript нечто похожее существует уже давно, хотя и косвенно — через деструктуризацию объектов и практику передачи целого объекта параметров в функции:
signIn({ username, password, otp_code: getOtp() });
Rust реализует подобный приём для структур, а в Ruby можно писать именованные аргументы так:
sign_in(username:, password:, otp_code: get_otp)
Мне этого не хватает в Python — и при передаче значений, и при распаковке словарей.
Но я никогда не был уверен, что именно этот синтаксис — удачный вариант: на первый взгляд он выглядит как синтаксическая ошибка, и есть в нём что-то тревожное.
В заявлении об отклонении Совет управляющих Python отметил:
Совет не уверен, что эта возможность — лучшее, что Python может предложить. Хотя мы признаём, что подобные решения могут улучшить некоторые сценарии, они должны быть сбалансированы со всем остальным. Как мы уже упоминали ранее, изменения грамматики проходят более строгую проверку, учитывая масштаб их влияния.
Я не собираюсь превращать все свои API в **kwargs
, так что, видимо, пока придётся жить с кучей повторяющихся аргументов в коде. Явное лучше, чем неявное, полагаю.
Но всё же — я ждал чуда.
Производительность Python 3.14 оказалась не такой уж впечатляющей
Последние несколько релизов Python принесли немало хорошего, но, к сожалению, они не оправдали шума вокруг обещанного прироста производительности. Похоже, с 3.14 ситуация будет такой же.
В этой версии появился новый опциональный интерпретатор с оптимизацией хвостовых вызовов, который, как казалось, давал в среднем прирост 10–15%.
Интерпретатор с оптимизацией хвостовых вызовов — это такой режим, где вызовы функций, выполняемые в самом конце перед возвратом результата, обрабатываются более эффективно, чтобы не раздувать стек вызовов без необходимости. В Python реализовать это особенно сложно: стек дорогой, но при этом является важной частью языка. Он доступен как публичный API, которым можно управлять прямо из программы, и именно он обеспечивает привычные и подробные трассировки при падении.
Поэтому ожидания были высокими.
Но, как заметил исследователь из Anthropic Нельсон Элхейдж, при практических экспериментах оказалось что-то не так. При сборке CPython GCC или Clang 18 (вместо LLVM 19) прирост сокращался до 1–5%. Выяснилось, что изначальные «плюсы» в основном объяснялись тем, что новая реализация непреднамеренно обходила регрессию в LLVM 19.
Конечно, не всё так плохо.
Во-первых, всё же остаётся несколько процентов ускорения. Во-вторых, баг был замечен и исправлен. Сделали выводы и подтянули методику бенчмарков. И, наконец, новый интерпретатор всё ещё имеет потенциал дать больше в будущем.
Но всё же это не лучший сезон для пони.
Депрекации в setuptools ломают проекты
Setuptools 78.0.1 окончательно убирает поддержку ключей в setup.cfg, где использовались дефисы вместо подчёркиваний. Эта возможность была помечена как устаревшая ещё в 2021 году, но проекты, которые до сих пор используют setuptools вместо более современных систем сборки, как правило, и обновляют свой инструментарий реже. Да и заметить предупреждение было легко не всем.
И вот теперь всё начинает сыпаться.
Если вы видите ошибку setuptools.errors.InvalidConfigError: Invalid dash-separated key
, у вас есть несколько вариантов: откатить setuptools, переименовать проблемный ключ или найти другую зависимость, если вы не можете управлять им напрямую.
Также стоит рассмотреть переход на hatchling, который хранит конфигурацию в pyproject.toml — он полностью декларативен, более быстр и обеспечивает лучшую изоляцию сборки.
А можно и не переходить — у меня до сих пор есть несколько проектов на setuptools, и они работают вполне нормально.
Если же вы не понимаете, о чём речь, возможно, я когда-нибудь напишу серию статей про пакетирование.
Новый формат lock-файла для Python готов
Совсем забыл упомянуть (что иронично, учитывая, что я следил за этим месяцами), поэтому добавляю уже после публикации.
PEP 751 — многолетняя эпопея Бретта Кэннона (интервью обязательно будет, обещаю, я просто опаздываю с опозданиями) за создание официального lock-файла для Python — наконец завершена. Цель состояла в том, чтобы определить формат файла, который перечисляет все зависимости проекта и связанную с ними информацию, позволяя воспроизвести то же самое окружение на другой машине.
Lock-файл — это не просто список прямых зависимостей проекта. Это ещё и список зависимостей этих зависимостей, их точных версий, источников, откуда их скачивать, плюс ещё куча метаданных, которые важны для точного воспроизведения. requirements.txt иногда используют как грубый аналог lock-файла, но он не обеспечивает надёжного воспроизведения окружения.
Это огромное достижение, ведь до сих пор существовало пять конкурирующих форматов lock-файлов, которые генерируют PDM, pip, pip-tools, Poetry и uv — каждый со своими компромиссами.
Спецификация довольно объёмная, но вот приведённые примеры (лучше смотреть оригинал: там есть цвета, а Substack их не поддерживает):
lock-version = '1.0'
environments = ["sys_platform == 'win32'", "sys_platform == 'linux'"]
requires-python = '==3.12'
created-by = 'mousebender'
[[packages]]
name = 'attrs'
version = '25.1.0'
requires-python = '>=3.8'
wheels = [
{name = 'attrs-25.1.0-py3-none-any.whl', upload-time = 2025-01-25T11:30:10.164985+00:00, url = 'https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl', size = 63152, hashes = {sha256 = 'c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a'}},
]
[[packages.attestation-identities]]
environment = 'release-pypi'
kind = 'GitHub'
repository = 'python-attrs/attrs'
workflow = 'pypi-package.yml'
[[packages]]
name = 'cattrs'
version = '24.1.2'
requires-python = '>=3.8'
dependencies = [
{name = 'attrs'},
]
wheels = [
{name = 'cattrs-24.1.2-py3-none-any.whl', upload-time = 2024-09-22T14:58:34.812643+00:00, url = 'https://files.pythonhosted.org/packages/c8/d5/867e75361fc45f6de75fe277dd085627a9db5ebb511a87f27dc1396b5351/cattrs-24.1.2-py3-none-any.whl', size = 66446, hashes = {sha256 = '67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0'}},
]
[[packages]]
name = 'numpy'
version = '2.2.3'
requires-python = '>=3.10'
wheels = [
{name = 'numpy-2.2.3-cp312-cp312-win_amd64.whl', upload-time = 2025-02-13T16:51:21.821880+00:00, url = 'https://files.pythonhosted.org/packages/42/6e/55580a538116d16ae7c9aa17d4edd56e83f42126cb1dfe7a684da7925d2c/numpy-2.2.3-cp312-cp312-win_amd64.whl', size = 12626357, hashes = {sha256 = '83807d445817326b4bcdaaaf8e8e9f1753da04341eceec705c001ff342002e5d'}},
{name = 'numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl', upload-time = 2025-02-13T16:50:00.079662+00:00, url = 'https://files.pythonhosted.org/packages/39/04/78d2e7402fb479d893953fb78fa7045f7deb635ec095b6b4f0260223091a/numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl', size = 16116679, hashes = {sha256 = '3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe'}},
]
[tool.mousebender]
command = ['.', 'lock', '--platform', 'cpython3.12-windows-x64', '--platform', 'cpython3.12-manylinux2014-x64', 'cattrs', 'numpy']
run-on = 2025-03-06T12:28:57.760769
Файл должен называться pylock.toml
или pylock.<что-то>.toml
.
Как и ожидалось, в нём зафиксированы условия окружения (включая ОС, платформу и версию Python); поддерживаются как wheels, так и исходные дистрибутивы (sdists), а также поддерживает ссылки на локальные ресурсы или удалённый репозиторий в VCS.
Ещё интереснее то, что для каждого файла указаны хэши, время публикации (upload time) и размер файла — для безопасности.
Вероятно, не все инструменты смогут его поддерживать, так как он не покроет все возможные сценарии. Но я уверен, что большинство хотя бы добавит возможность экспорта в этот формат.
Dependabot теперь поддерживает uv
Dependabot — это GitHub-бот, который проверяет зависимости проекта на предмет устаревания или уязвимостей и уведомляет об этом.
Это удобный способ держать проект в актуальном состоянии и своего рода подстраховка для самых простых и очевидных задач — обновлений и устранения уязвимостей, особенно учитывая, что он практически ничего не стоит.
До сих пор отсутствие поддержки uv не казалось мне проблемой: всегда можно было выполнить uv export в requirements.txt, который Dependabot понимает. Поэтому это было скорее неудобством, чем блокером.
Но я видел, что многие в сообществе жаловались, что для них это действительно мешало работе, ведь Dependabot умеет автоматически создавать пулл-реквесты с обновлением зависимостей. Я сам этим не пользуюсь, но понимаю, зачем это может быть нужно.
Так что завершу статью на позитивной ноте: теперь Dependabot официально поддерживает uv. Можно радоваться.
Если вас тоже утомляют бесконечные костыли и устаревшие практики, есть способ переключиться на что-то более прикладное. Иногда лучше один раз собрать рабочий прототип или разобраться в архитектуре, чем ждать очередного «сахара» в языке. Записывайтесь на бесплатные уроки, будем разбираться вместе:
10 сентября в 20:00 — Telegram-бот с нуля на Python: от теории к практике
23 сентября в 20:00 — Зависимости в FastAPI
Следить за обновлениями языка полезно, но реальный рост приходит через системное обучение. В OTUS есть курсы для разных уровней: специализация Python Developer помогает новичкам уверенно войти в профессию, а Python Developer. Professional даёт практику и инструменты для тех, кто уже пишет на Python и хочет выйти на новый уровень.
Комментарии (7)
zzzzzzerg
05.09.2025 11:34Презентация от автора про
tail-calling interpreter
https://docs.google.com/presentation/d/10oznjsxU45TzdwCrtLoK9cm3xcsavIYh2vlZ2RkWkhU/edit?slide=id.g344929f9bd2_1_6#slide=id.g344929f9bd2_1_6
SystemSoft
05.09.2025 11:34зачем делать такие сокращения??? вроде бы в пайтоне именованные аргументы можно и так:
#допустим оригинал add(one=1, two=2) #и как можно add(1, 2)
ПРОСТО передать аргументы как обычные.
morijndael
05.09.2025 11:34Не всегда. Аргументы в сигнатуре функции также можно пометить как «только позиционные» и «только именованные»
KonstantinTokar
05.09.2025 11:34Надо упрощать язык, иначе в погоне за сахаром программист пропустит что то более важное. Сахар усложняет синтаксис под видом упрощения.
vadimr
Хвостовые вызовы важны не столько из-за производительности, сколько из-за переполнения стека.
Ariki
Да там на самом деле совсем не то, о чём написано в статье. Не интерпретатор с оптимизацией хвостовых вызовов, а реализация интерпретатора байт-кода, оптимизированная за счёт трюка с использованием хвостовых вызовов.