19037
Полный Дзен Пайтона в одном канале Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Сайт: https://tprg.ru/site Регистрация в перечне РКН: https://tprg.ru/xZOL
Когда isinstance() мало, TypeGuard может удивить
С isinstance() всё просто: mypy сам сужает объединение типов в каждой ветке. Сложнее, если объект приходится распознавать по содержимому, например проверять поля словаря. Тогда проверку выносят в отдельный предикат, а TypeGuard сообщает анализатору, какой тип прошёл условие.
На этом месте интуиция может подвести: автор несколько раз отказывался от TypeGuard и заканчивал комментарием # type: ignore. В разборе TypeGuard и TypeIs он начинает с TypedDict для Person и объясняет, почему TypeIs соответствует ожиданиям лучше.
Стоит прочитать перед следующим пользовательским предикатом: в статье осталось главное, почему TypeIs оказался тем интерфейсом, которого автор ожидал от TypeGuard.
Все дела подождут, потому что сегодня ваш день!
Поздравляем с Днем программиста и желаем меньше багов и больше фич, меньше созвонов и больше фокуса, меньше тасок с пометкой «срочно» и больше времени на отдых.
Забирайте подарок из нашей IT-коробки. Мы уверены, этот презент точно пригодится вам в работе: https://tprg.ru/la2S
Контекст запроса можно добавить во все логи без ручного extra
В ASGI-приложении запрос заканчивается не там, где начался: обработчик вызывает корутины из других слоёв, и каждая пишет собственные сообщения. Если добавить user_id и platform через extra только в обработчике, запись из вложенной функции останется без этих полей.
Явное лучше неявного, но собирать один и тот же контекст в каждом слое и вручную передавать его дальше — дорогая трактовка PEP 20.
В разборе распространения контекста логов показано, как общие поля попадают в сообщения из разных слоёв ASGI-приложения без ручной передачи по всей цепочке вызовов.
Как найти хеш пароля в 37 ГБ меньше чем за миллисекунду
Офлайн-проверка пароля по списку утечек выглядит как обычный поиск, пока Pwned Passwords не распаковывается в текстовый файл на 37 ГБ. Минимальный вариант на Python работает, но оказывается слишком медленным.
Автор профилирует код, пробует пропускать части файла, применяет двоичный поиск, строит отдельный индекс и переводит его в двоичный формат. Вполне по дзену: сначала измерить, потом усложнять. Результат: поиск занимает меньше миллисекунды.
В разборе оптимизации можно проследить, почему первые ускорения не уложились в цель, как генерируется и читается индекс и какие структуры данных автор рассматривает в финале.
Сотни тысяч корутин лучше не запускать разом
Если запустить всю пачку асинхронных операций сразу, вы нагрузите вызываемые сервисы, а всё необходимое для работы окажется в памяти одновременно. Ограничение конкурентности нужно до того, как очередь съест ресурсы.
Питоничная цель напоминает imap_unordered(): одновременно выполнять не больше limit операций и отдавать результаты по мере готовности. asyncio.Semaphore кажется очевидным ответом из Stack Overflow, но автор предупреждает: лучший вариант другой.
В разборе ограничения конкурентности сопоставлены gather(), Semaphore, as_completed(), Queue и wait(). Читайте, чтобы понять, почему автор выбрал wait() и как собрал асинхронный map_unordered() с поддержкой итерируемых объектов и исключений.
Trame v4 добавил управление React-компонентами из Python
При создании приложения на Python-фреймворке trame теперь можно выбрать client_type="react" и сохранить привычные механизмы состояния, событий и триггеров. Связки react.Bind и react.Callback синхронизируют серверную логику с интерфейсом — без отдельного REST API и самописного обмена данными.
Обновление прежде всего пригодится организациям с готовыми React-библиотеками и дизайн-системами: их можно задействовать без полной переделки фронтенда. Но смены фаворита пока нет — Vue.js остаётся стандартным и наиболее полным клиентом, а Kitware не обещает паритета возможностей.
В статье перечислены поддерживаемые на старте компоненты и варианты рендеринга.
Код без GIL запускается одной командой, а зависимости к этому готовы не все
Проверка занимает вечер: ставите сборку python3.14t, прогоняете тесты и смотрите, где C-расширение роняет интерпретатор, а где два потока портят общий словарь. Со стороны CPython работа сделана: в 3.13 сборку без глобальной блокировки отдавали как экспериментальную, в 3.14 она стала официально поддерживаемой. Узкое место переехало в экосистему: пакет с C-кодом заводится в такой сборке, только если его пересобрали и проверили под неё.
На PyCon US 2026 Томас Ваутерс, который занимается CPython 25 лет и входит в steering council, прошёл по всей истории: зачем блокировку вообще снимали, что из этого получилось к сегодняшнему дню и станет ли сборка без GIL единственной. Конспект доклада опубликовал LWN.
#cpython
Сообщение об ошибке в Python подсказывает, где сломался код, если читать его с конца
Программа упала, в терминале простыня красного текста, которую хочется закрыть не читая. А имя ошибки и пояснение стоят в последней строке. NameError: переменной с таким именем нигде не создано, обычно опечатка. IndexError: вы просите шестой элемент у списка из пяти. Строки выше показывают файл и номер строки, где всё оборвалось.
Когда имя понятно, а причина нет, ставьте print перед подозрительным местом и сверяйте значения переменных с тем, что ожидали. Если print становится слишком много, включайте встроенный отладчик pdb: он останавливает программу в нужной точке и показывает значения прямо там. Хендбук freeCodeCamp по отладке разбирает имена ошибок подробнее и учит работать с pdb.
Возьмите ошибку, на которой застряли недавно, и разложите её по схеме: имя, пояснение, номер строки.
#python #основы
deepcopy копирует всё, до чего дотянется, включая то, что вы копировать не собирались
Знакомая поломка: конфиг сложили в словарь, сделали copy.copy, поправили вложенный список в клоне и увидели правку в оригинале. Новый контейнер получает те же ссылки на вложенные объекты.copy.deepcopy идёт по графу рекурсивно и ведёт словарь memo: каждый скопированный объект запоминается по id. Циклическая ссылка поэтому не уводит копирование в бесконечность, а два поля, смотревшие на один список, в копии тоже смотрят на один. Плата — обход всего графа: объект, который держит открытый сокет или пул соединений, deepcopy либо уронит, либо утащит за собой пол-приложения.
Поведение настраивается методами __copy__ и __deepcopy__: класс сам решает, что воспроизвести заново, а что отдать по ссылке.
Разбор поверхностной и глубокой копии — в статье на dev.to.
#python
ffmpeg вернул нулевой код возврата, а видео на выходе оказалось битым
Внешние утилиты из Python проверяют обычно одинаково: subprocess.run(..., check=True), и раз исключения нет, значит всё получилось. С ffmpeg этого мало: он спокойно отрабатывает с нулевым кодом и отдаёт файл, собранный не из тех фрагментов, которые вы просили, а заметить это можно, только досмотрев результат до конца.
В ReelCraft, CLI на Python для сборки ролика из папки с фото и видео, такое случилось трижды: Gemini 3.7 Flash разбирает ассеты и предлагает список нарезки, ffmpeg режет по нему, оба этапа отчитываются об успехе. Что именно разъехалось в склейке и субтитрах, разбирает дев-лог автора.
Приём оттуда полезен и без видео: между выводом модели и вызовом ffmpeg лежит edl.yaml, который человек читает и подтверждает руками. И проверять после subprocess стоит артефакт, тем же ffprobe, а не код возврата.
#python
Как выбрать между threading, asyncio и процессами, не переписывая код четыре раза
Модель конкурентности обычно берут ту, что уже стоит в соседнем модуле, а не ту, что подходит нагрузке. Пока задача упирается в сеть, ошибиться сложно: ждёт всё равно не процессор. На счётной задаче цена решения видна сразу.
В руководстве Real Python одна и та же задача написана в четырёх версиях: синхронной, на потоках, на asyncio и на процессах. И так дважды: сначала для нагрузки, где программа ждёт ответа по сети, потом для той, где она считает. Восемь реализаций одной задачи.
В статье остаётся разбор: чем заканчивается тот же прогон на счётной нагрузке, где процессы дают настоящий параллелизм, а где хватает управления ожиданием на одном ядре, и по какому признаку выбирать модель до того, как писать код.
#python
Соберите Discord-бота на Python и заодно разберитесь с асинхронностью
Со стороны бот выглядит сложно: отвечает на сообщения, помнит куски разговора, живёт круглосуточно. На деле это программа на Python, которая подключается к Discord, ждёт событие и решает, как на него ответить.
Как учебный проект он хорош тем, что за одного бота вы трогаете сразу несколько тем: команды, события, асинхронный Python, хранение состояния пользователя, переменные окружения и простейший деплой. Обычно это учат по отдельности и не видят, как оно соединяется.
Туториал начинает с совсем маленького бота и наращивает по одной функции. Каждый шаг можно запустить и увидеть результат, а не ждать финала.
#python
Соберите первую нейросеть на Python без матана и видеокарты
Слово «нейросеть» звучит так, будто нужен продвинутый матанализ, мощная машина и тысячи строк кода. Ничего из этого не нужно.
На базовом уровне нейросеть это математическая модель, которая берёт на вход числа, что-то с ними считает, выдаёт предсказание, сравнивает его с правильным ответом и подправляет себя, чтобы в следующий раз ошибиться меньше. Этот цикл и есть обучение, всё остальное надстраивается сверху.
В туториале такую сеть строят руками на Python и NumPy, без фреймворков, чтобы был виден каждый шаг. Хороший следующий шаг после основ языка: слова «слой», «веса» и «обучение» перестанут быть заклинаниями и станут строчками кода, которые вы написали сами.
#python
Что выбрать под неизменяемые объекты: обычный класс или dataclass
Обычный класс порождает изменяемые экземпляры, пока вы явно не запретите менять атрибуты. Отсюда и вопрос, который разбирает автор: где для неизменяемых данных проходит граница между ручным классом и dataclass.
В разборе три части: как сделать неизменяемость на голом классе, что даёт __slots__ для памяти и контроля атрибутов, и что из этого закрывает dataclass(frozen=True) без ручной работы.
Тема из тех, где каждый однажды принимает решение по привычке и живёт с ним годами. Хороший повод пересмотреть привычку на конкретных примерах.
В Python шесть предобъявленных констант, и каждая ведёт себя по-своемуTrue, False, None, __debug__, Ellipsis и NotImplemented. Автор разбирает, чем они отличаются, и различий больше, чем ожидаешь.
Первая тройка это вообще не идентификаторы, а собственные лексические токены: разрешаются в лексере, а не при обычном разрешении имён. Побочный эффект в том, что выражение x.True даёт SyntaxError, и больше в языке так не ведёт себя ничего.
Отдельный случай __debug__: обычный идентификатор, но единственный, которому нельзя присвоить значение, причём даже как атрибуту. При этом x.__debug__ даёт уже AttributeError, потому что синтаксически это законно. Хорошая заметка на вечер, если любите тёмные углы языка.
Атрибуты модуля можно создавать только при обращении
Если часть API не нужна во время запуска, готовить её заранее необязательно. Начиная с Python 3.7, в модуле можно определить __getattr__: он обрабатывает обращение к имени, которого в модуле нет.
Для нужного имени функция возвращает динамически созданное значение, для остальных поднимает AttributeError. Так создание атрибута переносится на момент, когда он действительно понадобился, а запуск не ждёт этой работы. Лень здесь вполне питонична, пока ошибка для неизвестных имён остаётся явной.
В разборе атрибутов модуля есть минимальный пример с обычной функцией, динамическим атрибутом и AttributeError для неизвестного имени.
Сигналы Django подводят в критичных сценариях, но получателей можно выполнять надёжнее
Сигналы Django удобно разрывают зависимости между модулями. В обработке платежа этого мало: способ доставки сигналов остаётся подвержен неожиданным сбоям. Слабая связанность полезна, но надёжность от неё не появляется.
Альтернативный способ запускает получателей как фоновые задачи Django Tasks. В материале решение проверяют на процессе создания платежа и заказа, связывают с транзакциями базы данных, моделируют сбои и отдельно рассматривают атомарность.
В статье Reliable Django Signals остались тесты надёжных сигналов, ограничения подхода и направления дальнейшей работы. Стоит прочитать до того, как доверить сигналам этап процесса, который нельзя потерять из-за неожиданного сбоя.
Как выбрать быстрый способ читать Excel из Python без сюрпризов с типами
Когда в Python нужно разобрать большой XLSX, привычный Pandas оказывается лишь одной из шести опций. Сравнивать их только по секундомеру мало: ещё важны сохранность типов и корректность значений.
Питоничность здесь начинается с контракта: каждая реализация возвращает Iterator[dict[str, object]], поэтому потребитель может обрабатывать строки по одной. Для теста взяли файл на 25 МБ с 500 тысячами строк, а время измеряли полным проходом без обработки данных.
В сравнении Haki Benita остались итоговые замеры для Pandas, Tablib, Openpyxl, LibreOffice, DuckDB и Calamine, а также разбор типов и корректности. Полезный ориентир перед тем, как ставить очередную зависимость ради одной таблицы.
Внешние ключи Django могут оставить лишние индексы и заблокировать миграцию
В модели всё выглядит аккуратно: несколько ForeignKey, on_delete=PROTECT и unique_together. Но внешний ключ связывает две таблицы, поэтому обеспечить такое ограничение сложнее, чем уникальность или проверку значения. Явное лучше неявного, а неявного поведения здесь хватает.
Статья How to Get Foreign Keys Horribly Wrong разбирает, где появляются дублирующие индексы и как обнаружить блокирующую миграцию. Затем переходит к безопасному переносу внешнего ключа, обратимым операциям и конкурентному созданию индексов.
Перед следующим изменением схемы по ссылке стоит проверить ещё две вещи: когда нужен частичный индекс и в каком порядке выполнять миграционные операции.
Дескриптор может удерживать ваши объекты, но слабые ссылки это исправят
Вы удалили экземпляр, а память не освободилась. Причина может прятаться в дескрипторе: если он записывает проверенные экземпляры в обычный dict, словарь сохраняет сильные ссылки. Сборщик мусора не удалит такие объекты, и утечка будет расти понемногу.
Если хранить сами экземпляры всё-таки нужно, замените словарь на слабый:
import weakref
_seen = weakref.WeakKeyDictionary()
Научные библиотеки сошлись на 3.14t как общей цели free-threading
Если вы держите отдельное окружение под сборку без GIL, зоопарк собранных колёс наконец сокращается: поддержку 3.13t крупные научные библиотеки убрали и целятся теперь только в 3.14t. Проверять свой код на свободных потоках можно на одной версии, а не на двух.
Что ещё случилось за август, Real Python собрал в месячном дайджесте:
• Python 3.15 выпустил финальную бету;
• команда JIT ответила Steering Council на его ультиматум;
• Astral выкатила ломающие миноры uv и Ruff: перед обновлением стоит заглянуть в changelog;
• MCP пережил крупнейшую переписку с момента появления: сессии выброшены, протокол стал stateless, а FastMCP в Python SDK переименовали.
#cpython
Диалап, Winamp, Живой Журнал — вспомни всё и за пару минут узнай свой цифровой архетип.
Читать полностью…
Язык, на котором вы пишете каждый день, десятый год подряд оплачивает в том числе Meta*
Python Software Foundation живёт на пожертвованиях, и Meta* десятый год подряд числится среди спонсоров. Python у них самый используемый язык, на нём держится бэкенд Instagram* и Threads*.
Деньгами участие не ограничивается. Часть core-разработчиков CPython работает в Meta*: они пишут фичи и PEP'ы, так что каким язык станет в следующем релизе, решают в том числе люди на зарплате компании. Оттуда же вышел PyTorch, позже переехавший в собственный фонд, и Pyrefly, тайпчекер с language server, который в компании называют очень быстрым.
Последнее проверяется дешевле, чем обсуждается: если mypy на вашем проекте прогоняется минутами, поставьте Pyrefly рядом и сравните время на том же коде.
#cpython
*Компания Meta и её продукты признаны экстремистскими, их деятельность запрещена на территории РФ.
Бэкап, украденный сегодня, расшифруют квантовой машиной через десять лет, и в Python от этого уже есть пакет
Зашифрованный архив можно скачать сейчас и спокойно подождать, пока появится машина, которая его вскроет: файлы на диске живут дольше, чем стойкость нынешних алгоритмов. На этот случай сделана библиотека Quipu: гибридное шифрование, где классическая схема X25519 и постквантовая ML-KEM-1024 работают вместе, так что контейнер откроется, только если падут обе сразу.
Питонисту она приезжает как pip install quipu-crypto, нативным колесом на PyO3; внутри Rust без сборщика мусора и без собственного unsafe. API короткий: encrypt_stream с decrypt_stream шифруют по паролю, generate_keypair с encode_to_recipient закрывают данные под конкретного получателя.
Заодно автор объясняет, почему из проекта исчезли слой C ABI и биндинги для Node и Go, которые были в первой версии.
Питонисту советуют TypeScript ради типов, которые у него уже есть
У питониста в CI давно стоит mypy, а аргументы за TypeScript ему перечисляют те же: типы ловят ошибки до запуска, интерфейсы фиксируют форму объекта, вывод типов экономит аннотации. Из этого набора собран и гайд для питонистов на dev.to.
Разница начинается дальше, в судьбе самих типов. В TypeScript они стираются при компиляции, и входящий JSON всё равно приходится проверять руками или через zod. В Python аннотации остаются в объекте: их читает pydantic, на них держится валидация в FastAPI, один и тот же тип работает и в проверке схемы, и в разборе запроса.
Одни считают, что после mypy в TypeScript идти незачем: тот же контракт, только с npm. Другие говорят, что tsc дисциплинирует сильнее mypy, который на чужом коде молча сдаётся на Any.
А по вашему опыту?
#python
JIT в CPython перестанет быть экспериментом, если обгонит free-threaded интерпретатор на 20%
JIT лежит в main с 3.13, и включать его до сих пор незачем. В 3.15 он даёт 4–12% ускорения (среднее геометрическое по платформам Tier 1), отдаёт кадры, которые нативные отладчики разматывают в нормальный стек, и занимает меньше памяти под сгенерированный код, чем в 3.14.
PEP 836 называет цену выхода из статуса «экспериментальный»: к первой бете сборка с JIT и free-threading должна обойти free-threaded интерпретатор без JIT минимум на 20% по среднему геометрическому на pyperformance. Плюс совместимость, инструменты, дистрибуция и модель поддержки.
То есть JIT и free-threading перестают быть двумя отдельными экспериментами, их сводят в одну цель. Прогнать свои бенчмарки на сборке с JIT стоит сейчас, пока цифры в PEP обсуждаются.
#cpython
Четыре джойна в SQL против одного запроса в графе: справочник по Neo4j и Python
Рамка задана вопросом, который легко произнести и тяжело написать: у каких инженеров есть свежий контекст по сервисам, задетым ночным инцидентом. В SQL это четыре или пять джойнов, каждый строит промежуточный результат шире нужного ответа и тут же выбрасывает большую часть. Запрос замедляется по мере роста таблиц и хуже читается с каждым возвращением к нему.
Справочник ведёт от пустой базы до работающего графа знаний: загрузка настоящих данных из Python и запросы, на которых идея становится понятной.
Разобраны части, которые туториалы пропускают: как решить, что становится узлом, почему первая модель данных почти наверняка неверна, как ускорить загрузку и как читать план запроса, когда что-то тормозит.
EVE Online начала переезд на Python 3 после двух десятилетий на второй ветке
Под каждым прыжком через гейт, каждым ордером на рынке и каждым флитфайтом в EVE лежит очень много Python. Он держит New Eden больше двадцати лет, и теперь CCP объявила о начале перехода на третью ветку.
Формулировка успеха у команды показательная: миграция должна пройти совершенно незаметно, если не считать моментов, когда что-то начнёт работать глаже. Первые шаги уже выкачены на тестовый сервер Singularity.
Это редкий публичный кейс переезда живого продакшена такого возраста. Обещают в итоге более быстрый поиск багов, место под новые фичи и общее ускорение, но дорога, по их же словам, длинная.
EPUB это ZIP с XHTML внутри, и собрать его обратно после правки труднее, чем разобрать
Сервис LectuLibre переводит книги через модели: пользователь загружает EPUB, бэкенд достаёт текст, отправляет его в Claude или DeepSeek и кладёт перевод обратно в тот же файл. Автор пишет, что именно последний шаг оказался самым тяжёлым.
EPUB это ZIP-архив с документами XHTML, стилями, картинками, шрифтами и служебными файлами вроде container.xml и content.opf. Вернуть переведённый текст на место, сохранив форматирование, изображения, стили и метаданные, значит собрать валидный контейнер заново.
В разборе есть выбор библиотек и компромиссы, на которые пришлось пойти. Пригодится, если строите любой конвейер обработки электронных книг.
Автор написал токенизатор, RoPE и SwiGLU руками и обучил модель на бытовой видеокарте
Развернуть Unsloth и дообучить Llama 3 за вечер несложно. Автор захотел посмотреть, что будет, если так не делать, и написал всё сам: BPE-токенизатор, RoPE, блоки SwiGLU и цикл обучения на чистом PyTorch.
Получилась EmsyAI версии 4 на 196,7 млн активных параметров: около 180 млн в блоках трансформера, остальное в эмбеддингах словаря примерно на 16 тысяч токенов. Обучение прошло на 1,96 млрд токенов и на потребительской видеокарте.
Ценность тут не в качестве модели, а в том, что каждый слой написан руками и его видно. Если вы читали про RoPE и SwiGLU, но не собирали их сами, это готовый маршрут.