19037
Полный Дзен Пайтона в одном канале Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Сайт: https://tprg.ru/site Регистрация в перечне РКН: https://tprg.ru/xZOL
За @property и @staticmethod стоят дескрипторы
Каждый раз, когда вы вешаете декоратор на метод, Python тихо создаёт объект с методом __get__. Этот объект ловит обращение к атрибуту класса и решает, что вернуть — bound method, вычисленное значение или сам дескриптор.
В свежем HOWTO от Рэймонда Хеттингера разобрано, как именно это работает: от примера, который всегда возвращает десятку, до чисто-питонических реализаций property и __slots__. Гайд пригодится, если хотите перестать догадываться и начать предсказывать поведение своих классов.
На Tproger вышла история разработчика с 10 годами опыта: с инженерной частью у него всё было закрыто, а для своего дела не хватало другого — проверять идею, считать деньги, доводить продукт до рынка. Онлайн-курсы он бросал на середине, поэтому выбрал формат пожёстче: онлайн-магистратуру МФТИ по технологическому предпринимательству.
В обзоре: как совмещать такую учёбу с работой, почему реальная нагрузка выходит 20–25 часов в неделю вместо заявленных 10, где программа слабая и во сколько она обойдётся в 2026 году.
@zen_of_python
80% корпоративных программ геймификации ломаются на одном и том же месте
По данным AmplifAI, игровые кампании дают в среднем вовлечённость на 100–150% выше, чем классические подходы, а геймифицированный контент шерится в 12 раз чаще. При этом примерно 80% корпоративных программ геймификации не достигают целей. Спрос огромный, качество — низкое, а причина проста: делать это берутся не те люди.
В статье разбирают, как корпоративные клоны механик упускают баланс и контекст, и что делать, чтобы прогрессия не превращалась в цифровой пендель. Для геймдевелоперов это отличная ниша, где есть и деньги, и возможность применить свои скиллы на практике.
Вышел mypy 2.2 — главное в релизе то, что тайпчекер научился закрытым TypedDict из PEP 728.
Что внутри:
🔘 TypedDict с closed=True запрещает любые ключи сверх объявленных — раньше лишние ключи в значении типа TypedDict были формально допустимы, и тайпчекер не мог на них ругаться;
🔘 закрытость делает надёжным сужение типов: в объединении Book | DVD проверка "author" in item теперь честно доказывает mypy, что перед ним Book;
🔘 работает и в классовом синтаксисе: class Book(TypedDict, closed=True);
🔘 завершена поддержка дефолтов типовых переменных из PEP 696 — и в старой записи TypeVar("T", default=int), и в новой class Box[T = int], включая рекурсивные дефолты;
🔘 mypy теперь уважает явно аннотированный тип возврата у __new__ — раньше он молча считал, что __new__ всегда возвращает экземпляр текущего класса;
🔘 поддержка TypeForm перестала быть экспериментальной.
Пользуетесь TypedDict для словарей с фиксированной структурой или в таких местах у вас dataclass и pydantic?
@zen_of_python
Пример прикладной робототехники: на хакатоне «Робозон» участники собирают интеллектуальную систему сортировки товаров.
Задачи охватывают весь цикл — детекция и классификация объектов, трекинг на конвейере, планирование захвата и управление манипулятором. За интеграцию отвечает связка компьютерного зрения с ROS.
В ход идут Python, OpenCV, PyTorch/Detectron2, ROS/ROS2 и симуляторы вроде Isaac Gym и CoppeliaSim. Отдельный слой — имитационное моделирование движения товаров и проектирование конструкции самого сортировщика.
Финальные решения команды покажут на конференции E-CODE. Описание задач лежит в открытом доступе, если интересно посмотреть постановку.
Django выпустил плановые security-релизы 6.0.7 и 5.2.16 — закрыты три уязвимости, и у каждой любопытный механизм:
🔘 кэш-мидлварь UpdateCacheMiddleware и декоратор cache_page не кэшировали ответ с Set-Cookie, только если входящий запрос был совсем без cookie. Если у пользователя уже была любая безобидная cookie вроде выбора темы, защита не срабатывала — и ответ с чужой сессионной cookie мог осесть в общем кэше;
🔘 при создании GDALRaster из bytes свойство vsi_buffer могло прочитать примерно 32 байта за границей буфера — с риском утечки соседней памяти кучи, а в редких случаях и падения процесса;
🔘 DomainNameValidator пропускал переносы строк в доменных именах — если такое значение попадало в HTTP-ответ, открывалась инъекция заголовков.
Первые две помечены низкой серьёзностью, но команда рекомендует обновиться как можно скорее всем.
Обновляете Django сразу после security-релизов или ждёте планового окна?
@zen_of_python
Cursor против Windsurf: что выбрать питонисту
Real Python сравнил два редактора на примере отказоустойчивого HTTP-клиента. Оба работают поверх VS Code, но подходят к ИИ по-разному: Cursor выводит агента, который правит код по запросу, а Windsurf предлагает Cascade с авто-выполнением команд в терминале.
Для питониста разница в деталях: Cursor Tab и Windsurf Tab по-разному дополняют код; в отладке Cursor использует inline-обзор и Bugbot, а Windsurf полагается на авто-линтинг. Раньше приходилось прыгать между редактором и отдельным ИИ-чатом, теперь оба инструмента пытаются убрать это трение.
Если пишете много асинхронного Python, имеет смысл протестировать оба и сравнить на своих задачах.
В Python появится встроенный frozendict: Steering Council принял PEP 814, и тип уже доступен в бета-версиях Python 3.15. Виктор Стиннер, соавтор PEP, рассказал историю вопроса: его первую попытку, PEP 416, Гвидо отклонил ещё в 2012 году.
Что внутри:
🔘 неизменяемый словарь: попытка присвоить элемент даёт TypeError;
🔘 хешируемый, если хешируемы все значения, так что его можно класть в set и использовать как ключ словаря;
🔘 сохраняет порядок вставки, но сравнение и хеш от порядка не зависят;
🔘 поддерживает объединение через | и сравнение с обычным dict.
Главное отличие от types.MappingProxyType в том, что прокси остаётся обёрткой над живым словарём, а frozendict — самостоятельный неизменяемый тип со своим хешем.
Ждёте frozendict в 3.15 или вам хватало MappingProxyType?
@zen_of_python
У Python появится отдельный совет по паковке — назначили даты первых выборов
После того как Steering Council в апреле утвердил PEP 772, PSF объявила даты первых выборов в новый Python Packaging Council: технический орган, который берёт на себя решения по спецификациям совместимости пакетов.
Совет состоит из пяти мест: два кандидата с наибольшим числом голосов получают двухлетний срок, а три оставшихся получают годовой. Голосование пройдёт параллельно с выборами PSF Board 2026.
Даты, если планируете участвовать:
🔘 28 июля: открытие номинаций;
🔘 11 августа: закрытие номинаций;
🔘 13 августа: публикация списка кандидатов;
🔘 25 августа: дедлайн подтверждения намерения голосовать;
🔘 1–15 сентября: само голосование.
Голосовать смогут члены PSF уровня Contributing, Supporting или Fellow, которые заранее подтвердят намерение участвовать.
Управление пакетным хозяйством Python годами было разбросано между pip, PyPA, отдельными PEP и добровольцами-энтузиастами. Кажется ли вам, что выделенный совет реально наведёт порядок, или это ещё один орган для лишних согласований?
@zen_of_python
uv 0.11.26 — резолвер зависимостей ускорили сразу с четырёх сторон
uv — быстрый пакетный менеджер и резолвер зависимостей для Python на Rust, замена pip и pip-tools в одном бинарнике. Версия 0.11.26 вышла 30 июня и целиком посвящена скорости резолвинга.
Что ускорили:
🔘 зависимости в PubGrub теперь передаются как ID вместо полных структур, это снижает накладные расходы на каждой итерации резолвера;
🔘 убрали лишние аллокации в ForkMap::contains, структуре, которая проверяет пересечения версий между форками резолвера;
🔘 резолвер стал переиспользовать уже проделанную работу между итерациями PubGrub вместо пересчёта с нуля;
🔘 ускорили выбор кандидата версии для непересекающихся диапазонов зависимостей.
Заодно поправили мелочь: uv теперь предупреждает, если build cache случайно оказался внутри директории с исходниками проекта.
Резолвер зависимостей редко попадает в заголовки, но именно на нём держится ощущение «uv install мгновенный». Вы уже увидели разницу в скорости на своих проектах, или для небольших requirements.txt она и так была незаметна?
@zen_of_python
Где держать Telegram-бота или API, чтобы они не падали под нагрузкой и не съедали бюджет?
Tproger собрал подборку из шести VPS-провайдеров под этот сценарий: от тарифов за пару сотен рублей в месяц до конфигураций с DDR5 и портом 10 Гбит/с. У каждого свой акцент — где-то посуточная оплата и запуск за минуту, где-то API для CI/CD, бэкапы и приватные сети, где-то зарубежные локации.
Внутри по каждому провайдеру: реальные конфигурации, цены, на какой нагрузке тестировали и под какой сценарий брать.
https://tproger.ru/articles/gde-razvernut-bota-ili-api---podborka-vps--kotorye-ne-tormozyat
Отправка почты из Python: stdlib, локальный SMTP и сторонние библиотеки
В стандартной библиотеке Python для работы с почтой есть пакет email и модуль для SMTP-соединений: формируете сообщение, добавляете вложения и адресатов, подключаетесь к серверу и отправляете. Для отладки удобно поднять локальный SMTP-сервер — письма не уйдут в интернет, но вы увидите, как они собираются.
Явное лучше неявного, но ручная сборка писем со временем утомляет. Статья разбирает сторонние инструменты вроде Yagmail и transactional email-сервисов, чтобы вы могли выбрать между «всё под контролем» и готовым решением.
Кому полезно: тем, кто отправляет уведомления, рассылки или отчёты из Python и хочет сравнить подходы.
⚡️ AI-инструменты можно любить и ненавидеть, но работать без них в IT уже практически невозможно!
Коллеги из AvitoTech 11 июля зовут в их офис на Лесной на AI Hardcore Day. Приглашают тех, кто каждый день сталкивается с AI в работе и даже пишет своих AI-агентов. Обещают доклады и нетворкинг-сессию на террасе после — и всё это без записи.
✔️ Среди тем:
— Spec-Driven Development: теория, инструменты, практика;
— Разработка и тестирование MCP для внутренних агентных систем аналитики;
— Выпрямляем руки агентов: как сделать MCP удобными и действительно полезными;
— Атаки на GenAI-агентов: OWASP на практике.
➡️ Регистрация тут!
Это #партнёрский пост
На python.org можно было войти как админ с любым API-ключом
Если в API python.org подсунуть имя администратора и произвольный ключ, система пропускала запрос с правами администратора. Никакого перебора, никакой магии — просто имя пользователя и левый ключ.
При этом атакующий не мог переписать сами файлы, но мог поменять URL для скачивания каждого релиза и ссылки на проверочные материалы Sigstore и PGP. Python Insider пишет, что баг пролежал в коде с 2014 года. Корпоративный перевод: «мы не трогаем бинари, мы только подменяем, куда вы их качаете».
Команда безопасности Python получила отчёт 23 февраля и закрыла уязвимость менее чем за 48 часов. Артефакты проверили по подписям, следов вмешательства не нашли. Сайт уже пропатчен.
Появился PEP 835, который предлагает сократить запись Annotated. Если пишете на Pydantic, FastAPI, Typer или SQLModel, вы видели это каждый день:
id: Annotated[int, Field(gt=0)]
name: Annotated[str, Field(min_length=3)]
@ для метаданных типа:id: int @ Field(gt=0)
name: str @ Field(min_length=3)
Annotated, просто запись короче.@ связывает сильнее, чем |: запись int | str @ Meta читается как int | Annotated[str, Meta], а для объединения с метаданными нужны скобки (int | str) @ Meta;T @ m1 @ m2 разворачивается в плоскую Annotated[T, m1, m2], без вложенности;types.AnnotatedType на C, а typing.Annotated станет ссылкой на него;Annotated[X, Y] никуда не денется, остаётся для совместимости.typing_extensions.
Altair: графики через описание данных, а не ручная настройка каждой оси
В духе Zen of Python: простое лучше сложного. Если в Matplotlib вы сначала объявляете фигуру, потом крутите оси и legend, то в Altair вы просто говорите DataFrame, какую колонку на какую ось положить, что раскрасить и как сделать интерактивным. Библиотека сама строит визуализацию из HTML и JavaScript, которая работает в ноутбуке или сохраняется отдельным файлом.
Real Python советует ставить Altair в выделенное виртуальное окружение: вместе с ним приезжают pandas и Vega-Lite-рендерер, и лучше не мешать их с остальным окружением.
Это не замена Matplotlib. Для пиксельно точных публикационных фигур или 3D по-прежнему стоит брать Matplotlib; для интерактивного исследования в ноутбуке — Altair удобнее.
Репозиторий python-patterns: каталог паттернов, которые стоит выбирать с умом
В python-patterns собраны классические паттерны и идиомы Python — 42,8k звёзд, 7k форков и 896 коммитов. Сообщество использует его как шпаргалку, чтобы быстро вспомнить, как выглядит тот или иной подход в коде.
Авторы явно предупреждают: каждый паттерн несёт свои компромиссы, а выбирать нужно не по красоте реализации, а по ситуации. В Python это особенно актуально — язык сам даёт идиомы, от итераторов до менеджеров контекста, и часто проще использовать встроенное, чем городить фабрику.
Полезно сохранить на тот момент, когда вам хочется применить паттерн ради паттерна. Иногда достаточно обычной функции.
Go-рутины в Python без async/await
Runloom экспериментально возвращает Python к простоте блокирующего кода: вызываете fiber(fn), пишете обычный recv/send или urlopen, а библиотека паркует задачу на сокете и переключает контекст. Никакого async def, никакого await — как до эпохи asyncio, но с миллионом лёгких потоков на всех ядрах.
Под капотом: hand-rolled ассемблерный context switch, work-stealing scheduler на C и netpoll. Цель: free-threaded Python 3.14t с выключенным GIL, когда один процесс действительно может загрузить все ядра, а не притворяться многопоточным.
Репозиторий на GitHub.
Метакласс: не магия, а ещё один уровень явности Python
Если класс — фабрика объектов, то метакласс играет роль фабрики самих классов. В Python 3 это не опция, а дефолт: любой ваш класс является экземпляром type, а class Foo: pass раскрывается в type('Foo', (), {}).
Свой метакласс наследуется от type и переопределяет __new__ или __init__. Он позволяет собирать, изменять или регистрировать классы программно, но в Python явность важнее изящества. В большинстве случаев ту же задачу решают наследование или декоратор класса.
Отсюда следует, почему в Python всё есть объект, включая само определение класса. Разбираемся в деталях.
Как собрать разрозненный Python в одну картинку
Real Python предлагает проверить понимание концепций языка тремя шагами: объяснить концепцию своими словами, найти ей знакомый аналог и применить в маленькой задаче.
Суть — не зубрить, а увидеть, как идея работает в коде. Возьмите тему, которую пока не чувствуете, и опишите её так, будто соседу по парте. Да, тот самый метод утёнка. Потом дайте себе пять минут и сравните её с похожей. Разница, которую вы сформулируете словами, лучше конспекта покажет, где остались дыры.
Ваша память ещё работает или нейронки уже и помнят всё за вас?
Чтобы это проверить мы приготовили для вас «Меморину» — игру, которая поможет проверить вашу память.
Всё просто: нужно запомнить и выбрать одинаковые карточки. Если память плохая, то рано или поздно вы всё равно справитесь. А если хорошая, то сможете увидеть ваш потолок скорости.
Ну что, готовы проверить? Тогда переходите по ссылке: https://tprg.ru/ydAe
⚡️AvitoTech устраивает онлайн CTF с призами до 300 000 рублей команду
Что внутри турнира: таски на веб-уязвимости, инфраструктурные мисконфиги, анализ скомпилированного кода, расследование инцидентов, слабости шифров и всё, что требует хакерской смекалки. Если это ваш первый опыт, вписывайтесь в Honey-лигу — туда опытных игроков не пускают.
➡️ Регистрация уже открыта
Кажется, это знак собрать свою команду и попробовать себя в роли того самого медоеда! Проверьте защиту пчелиного улья и помогите найти все скрытые уязвимости в сотах!
Вышла третья бета Python 3.15 — предпоследняя перед релиз-кандидатом, который намечен на 4 августа. Набор фич зафиксирован, так что уже понятно, что войдёт в релиз:
🔘 ленивые импорты для ускорения старта (PEP 810);
🔘 встроенные типы frozendict (PEP 814) и sentinel (PEP 661);
🔘 сэмплирующий профайлер Tachyon и отдельный пакет для организации инструментов профилирования (PEP 799);
🔘 распаковка в comprehensions (PEP 798) и UTF-8 как кодировка по умолчанию (PEP 686);
🔘 заметно ускоренный JIT: 8–9% среднего прироста на x86-64 Linux относительно обычного интерпретатора, 12–13% на macOS/AArch64;
🔘 стабильный ABI для free-threaded сборок.
В самой бете 195 исправлений от 86 контрибьюторов, последняя бета выйдет 18 июля. Разработчикам библиотек самое время прогнать тесты на 3.15 и собрать пререлизные wheels.
Уже пробовали 3.15 на своих проектах или ждёте стабильного релиза?
@zen_of_python
django-scroll-to-top: кнопка «наверх», которая не ломается в проде
Кнопка «наверх» кажется мелочью, пока в проде не всплывают cookie-баннер, чат поддержки, нижняя мобильная навигация и строгий CSP. Автор собрал типовые условия в Django-пакет django-scroll-to-top: один template-тег, Django Admin, настройка цвета и положения через админку без правки шаблонов.
Без jQuery, CDN и обязательной сборки. Если JavaScript выключён, остаётся обычная ссылка в начало страницы. Если в ваших Django-проектах кнопку надоело таскать между шаблонами, я бы заглянул в разбор на Tproger.
Вышла CPython 3.15.0b3 — предпоследняя бета перед заморозкой
23 июня вышла третья из четырёх бета-версий Python 3.15: около 195 правок от 86 контрибьюторов со времён второй беты. Набор фич уже заморожен, дальше только багфиксы и шлифовка. Release candidate назначен на 4 августа, финальный релиз на 1 октября, и команда просит прогнать свой код на бете, чтобы поймать регрессии и поломки ABI заранее.
Что приедет в серии 3.15 по сравнению с 3.14:
🔘PEP 686: UTF-8 становится кодировкой по умолчанию, открытие файлов без явного encoding больше не зависит от локали системы;
🔘PEP 810: явные ленивые импорты, модуль грузится при первом обращении, а не на старте программы, это срезает время запуска тяжёлых утилит;
🔘PEP 814: встроенный тип frozendict, неизменяемый словарь без сторонних библиотек;
🔘PEP 661: встроенный sentinel для значений-маркеров вместо самодельных объектов-заглушек;
🔘PEP 798: распаковка через * и ** прямо внутри list- и dict-comprehension;
🔘PEP 799: отдельный пакет для профилирования и Tachyon, высокочастотный статистический сэмплер.
@zen_of_python
Pathway — Python-фреймворк для потоковой обработки данных на Rust-движке
Pathway даёт писать на Python пайплайны реального времени: чтение из источника, преобразования, запись в приёмник, а тяжёлая часть считается Rust-движком. Тот же код работает и на пакетных данных, и на бесконечном потоке. Релиз v0.31.1 вышел 12 июня, на GitHub больше 62 тысяч звёзд.
Этот релиз почти целиком про новые коннекторы к базам:
🔘pw.io.elasticsearch.read читает индекс Elasticsearch: своего механизма отслеживания изменений у него нет, поэтому коннектор опрашивает и сверяет пересечение соседних запросов, чтобы ни одна строка не потерялась и не пришла дважды;
🔘pw.io.clickhouse.write пишет в ClickHouse по нативному протоколу, в двух режимах: поток изменений с колонками time и diff либо снапшот текущего состояния в ReplacingMergeTree;
🔘pw.io.mysql.read делает полноценный захват изменений через бинлог MySQL: сначала снимок таблицы, потом непрерывная доставка вставок, обновлений и удалений;
🔘расширили чтение Iceberg, теперь декодируются все примитивные типы, включая date, time, uuid, fixed и decimal;
🔘у коннекторов Postgres добавили набор проверок на старте, чтобы кривая конфигурация падала понятной ошибкой ещё до молчаливой потери строк.
Пригодится дата-инженерам, которые строят аналитику и ETL реального времени и устали склеивать поток из десятка разных коннекторов вручную.
https://github.com/pathwaycom/pathway
Язык: Python и Rust. Лицензия: BSL-1.1.
@prog_tools
time.sleep() — не везде правильный способ подождать
В синхронном скрипте time.sleep(2.5) идиоматичен: пауза в текущем потоке, никаких сюрпризов. Но в отдельном потоке ту же паузу не прервать по сигналу: лучше threading.Event().wait(), который просыпается по event.set().
В асинхронном коде time.sleep() заморозит весь event loop, потому что корутина не уступает управление. Правильный инструмент: await asyncio.sleep(), он приостанавливает только текущую задачу.
В гайде ещё про декоратор retry, rate limit и паузы в GUI через root.after().
Виктор Стиннер, один из ключевых разработчиков CPython, разобрал в блоге, как устроен PyMutex, замок размером в один байт, на котором держится free-threaded Python.
Зачем такой маленький? В режиме без GIL блокировка нужна на каждый объект отдельно: свой замок у каждого dict, list, set. Старый замок через py_recursivelock_t занимает 72 байта. Для сравнения, пустой список в Python 3.13 весит 56 байт, пустой словарь 64. Вешать по 72 байта на каждый объект невозможно. PyMutex решает это: один байт, из которого реально используются два бита под состояния (свободен, занят, занят с ожидающими потоками).
Что показали замеры. Дизайн взят из WebKit, у их движка есть WTF::Lock, а под капотом лежит _PyParkingLot, кроссплатформенный аналог futex. На захвате и освобождении без конкуренции:
🔘Linux x86-64: PyMutex 11 нс против 44 нс у старого замка, в 4 раза быстрее;
🔘macOS arm64: 13 нс против 18 нс, в 1,4 раза;
🔘Windows x86-64: 13 нс против 38 нс, в 2,9 раза.
Оговорка для авторов C-расширений: напрямую PyMutex использовать не стоит, легко словить взаимоблокировку. Для защиты доступа к объектам есть critical section API, Py_BEGIN_CRITICAL_SECTION(obj).
@zen_of_python
FastAPI выкатил два релиза подряд, 0.137.0 и 0.138.0, и оба меняют привычные вещи. Самое заметное снаружи появилось в 0.138.0: метод app.frontend().
Теперь собранный фронтенд раздаётся прямо из FastAPI, без отдельного nginx или статик-сервера:
app.frontend("/", directory="dist")dist, одна строка, и приложение само отдаёт его на корне. Есть и router.frontend() для поддерева.include_router() клонировал каждый путь в один плоский список, и в итоге на всё приложение оставался один роутер;APIRouter и APIRoute сохраняются, а router.routes стал деревом промежуточных объектов;include_router(), изменения подхватятся, потому что роуты не копируются;router.routes как по плоскому списку APIRoute, он сломается, теперь это дерево. Для таких сценариев в 0.137.2 добавили iter_route_contexts().
aiohttp выпустил 3.14.0 — крупный минорный релиз асинхронного HTTP-клиента и сервера. Упор на типобезопасность и быструю работу с JSON.
Что внутри:
🔘 типобезопасные ключи контекста RequestKey и ResponseKey вместо строковых ключей в request[...] — промах по типу теперь ловит чекер, а не прод;
🔘 работа с JSON прямо в байтах: json_bytes_response и send_json_bytes отдают уже сериализованные байты, без лишнего прохода через строку;
🔘 в WebSocket появился decode_text — получить TEXT-фрейм сразу как bytes и скормить его, например, orjson;
🔘 encode_basic_auth для аккуратной сборки заголовка Basic-аутентификации;
🔘 cleanup-контексты приложения теперь умеют асинхронные менеджеры контекста.
Если держите сервисы на aiohttp, апгрейд бесплатно даёт и более строгие типы, и меньше накладных расходов на JSON под нагрузкой.
@zen_of_python