Zen of Python
Полный Дзен Пайтона в одном канале Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Сайт: https://tprg.ru/site Регистрация в перечне РКН: https://tprg.ru/xZOL
Mostrar más📈 Análisis del canal de Telegram Zen of Python
El canal Zen of Python (@zen_of_python) en el segmento lingüístico de Ruso es un actor destacado. Actualmente la comunidad reúne a 19 241 suscriptores, ocupando la posición 6 971 en la categoría Tecnologías y Aplicaciones y el puesto 34 978 en la región Rusia.
📊 Métricas de audiencia y dinámica
Desde su creación el невідомо, el proyecto ha mostrado un crecimiento acelerado, reuniendo a 19 241 suscriptores.
Según los últimos datos del 23 junio, 2026, el canal mantiene una actividad estable. En los últimos 30 días la variación de miembros fue de -12, y en las últimas 24 horas de -9, conservando un alto alcance.
- Estado de verificación: No verificado
- Tasa de interacción (ER): El promedio de interacción de la audiencia es 11.48%. Durante las primeras 24 horas tras publicar, el contenido suele obtener 5.16% de reacciones respecto al total de suscriptores.
- Alcance de las publicaciones: Cada publicación recibe en promedio 2 209 visualizaciones. En el primer día suele acumular 993 visualizaciones.
- Reacciones e interacción: La audiencia responde de forma activa: el promedio de reacciones por publicación es 15.
- Intereses temáticos: El contenido se centra en temas clave como github, rust, pip, api, install.
📝 Descripción y política de contenido
El autor describe el recurso como un espacio para expresar opiniones subjetivas:
“Полный Дзен Пайтона в одном канале
Разместить рекламу: @tproger_sales_bot
Правила общения: https://tprg.ru/rules
Другие каналы: @tproger_channels
Сайт: https://tprg.ru/site
Регистрация в перечне РКН: https://tprg.ru/xZOL”
Gracias a la alta frecuencia de actualizaciones (últimos datos recibidos el 24 junio, 2026), el canal mantiene la vigencia y un amplio alcance. La analítica demuestra que la audiencia interactúa activamente con el contenido, lo que lo convierte en un punto de referencia dentro de la categoría Tecnologías y Aplicaciones.
app.frontend().
Теперь собранный фронтенд раздаётся прямо из FastAPI, без отдельного nginx или статик-сервера:
app.frontend("/", directory="dist")
Кладёте билд SPA в dist, одна строка, и приложение само отдаёт его на корне. Есть и router.frontend() для поддерева.
Под капотом в 0.137.0 переписали то, как роутеры включаются друг в друга:
🔘раньше include_router() клонировал каждый путь в один плоский список, и в итоге на всё приложение оставался один роутер;
🔘теперь исходные объекты APIRouter и APIRoute сохраняются, а router.routes стал деревом промежуточных объектов;
🔘из-за этого маршруты можно добавлять в подроутер уже после include_router(), изменения подхватятся, потому что роуты не копируются;
🔘в части случаев это ещё и экономит память.
Здесь же спрятан ломающий момент: если ваш код ходил по router.routes как по плоскому списку APIRoute, он сломается, теперь это дерево. Для таких сценариев в 0.137.2 добавили iter_route_contexts().
@zen_of_pythonAnnotated. Если пишете на Pydantic, FastAPI, Typer или SQLModel, вы видели это каждый день:
id: Annotated[int, Field(gt=0)] name: Annotated[str, Field(min_length=3)]PEP предлагает оператор
@ для метаданных типа:
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] никуда не денется, остаётся для совместимости.
Сокращение нацелено на Python 3.16, до этого его можно будет пробовать через typing_extensions.
@zen_of_pythonRequestKey и ResponseKey вместо строковых ключей в request[...] — промах по типу теперь ловит чекер, а не прод;
🔘 работа с JSON прямо в байтах: json_bytes_response и send_json_bytes отдают уже сериализованные байты, без лишнего прохода через строку;
🔘 в WebSocket появился decode_text — получить TEXT-фрейм сразу как bytes и скормить его, например, orjson;
🔘 encode_basic_auth для аккуратной сборки заголовка Basic-аутентификации;
🔘 cleanup-контексты приложения теперь умеют асинхронные менеджеры контекста.
Если держите сервисы на aiohttp, апгрейд бесплатно даёт и более строгие типы, и меньше накладных расходов на JSON под нагрузкой.
@zen_of_pythongrouped_bar() — группированные столбчатые диаграммы из коробки, без ручной возни со смещениями;
🔘 размеры фигуры можно задавать в px и cm, а не только в дюймах;
🔘 pie_label для подписей на круговых диаграммах;
🔘 отдельный hatchcolor — цвет штриховки независимо от цвета контура;
🔘 встроенные палитры Okabe-Ito и Petroff, дружелюбные к дальтоникам;
🔘 улучшения 3D-графиков и интерактивности.
Группированные бар-чарты и нормальная интернационализация подписей — то, вокруг чего годами городили костыли. А вы что чаще рисуете в Matplotlib?
@zen_of_pythonfit был чёрным ящиком: запустил и ждёшь. Теперь на estimator можно повесить колбэки через set_callbacks():
🔘 ProgressBar рисует прогресс обучения прямо в Jupyter или терминале;
🔘 ScoringMonitor следит за метрикой по ходу обучения, а не только в самом конце.
Что ещё в релизе:
🔘 metric_at_thresholds сразу считает метрики бинарной классификации по сетке порогов, без ручного перебора;
🔘 конфиг sparse_interface переводит трансформеры на sparse arrays вместо устаревших sparse matrices;
🔘 HTML-репр обученной модели теперь показывает не только параметры, но и fitted-атрибуты;
🔘 под капотом перешли на narwhals — библиотека лучше дружит с разными датафреймами, не только с pandas.
Колбэки — та фича, которой не хватало годами: видеть, что многочасовой fit реально движется, а не завис. Уже обновились или пока сидите на проверенной версии?
@zen_of_pythonLiteral["a", "b"], редактор предложит ровно эти значения;
🔘 рефакторинги «вынести функцию или класс в новый модуль» и «перенести символ в другой файл» с автоматическим переписыванием импортов;
🔘 навигация по pytest-фикстурам: от использования фикстуры можно прыгнуть к её определению;
🔘 новый LSP-endpoint getExpectedType: редактор спрашивает у чекера, какой тип ожидается в текущей позиции, и подсказывает точнее;
🔘 команда pyrefly coverage check показывает, насколько код покрыт аннотациями типов.
А вы уже пробуете быстрые чекеры на Rust или пока остаётесь на mypy?
@zen_of_pythonCounter не только считает, но и сразу выдаёт топ: Counter(words).most_common(3);
🔘defaultdict(list) избавляет от проверок if key in dict при группировке;
🔘itertools.groupby работает только на отсортированных данных — классическая ловушка;
🔘functools.partial замораживает аргументы: basetwo = partial(int, base=2);
🔘ChainMap собирает конфиг по приоритету: ChainMap(user_settings, defaults);
🔘@dataclass(frozen=True) даёт неизменяемый объект с __eq__ и __hash__ из коробки.
@zen_of_pythonruff format --check споткнулся о нарушение форматирования в _hooks.py;
🔘потом ruff check нашёл E402 (импорт не в начале файла) и I001 (несортированные импорты) в __init__.py.
Пайплайн красный, релиз не собрался, стилер до пользователей не доехал. Атакующий получил полный доступ на запись в репозиторий и споткнулся о проверку сортировки импортов.
Разбор инцидента опубликовала StepSecurity, и вывод из него шире смешного заголовка. Строгий линтинг в CI — это не только про красоту кода. Вредоносные инъекции почти всегда выглядят чужеродно: обфусцированные блобы, импорты посреди файла, нетипичное форматирование. Линтер с жёсткими правилами превращается в дешёвый детектор аномалий, который не обойти, не понимая кодстайл проекта.
Так что когда в следующий раз будете ворчать на красный пайплайн из-за несортированных импортов — вспомните, что ровно эта проверка спасла проект на 33 тысячи звёзд.
@zen_of_pythonuv audit. Сканирует зависимости проекта по базе OSV на известные уязвимости и заброшенный статус пакетов. Работает в 4-10 раз быстрее pip-audit — фирменный стиль Astral на месте.
Вторая интереснее: проверка на малварь прямо при установке. С переменной окружения UV_MALWARE_CHECK=1 команды uv add и uv sync сверяют залоченные зависимости с MAL-записями OSV и блокируют установку известной малвари до того, как её код вообще запустится. Учитывая, что свежие PyPI-кампании прячут стилеры в .pth-хуки, которые срабатывают при каждом старте интерпретатора даже без импорта пакета, проверка до установки — единственный момент, когда ещё не поздно.
В планах у Astral резолвер, который сам избегает уязвимых версий при разрешении зависимостей, и режим предупреждений только для новых зависимостей, чтобы не тонуть в алертах по старым.
Обе фичи в preview, но включить UV_MALWARE_CHECK в CI можно уже сейчас — бесплатная страховка. Кто на uv, попробуйте uv audit на своём проекте и расскажите, сколько насыпало.
@zen_of_python.remote(ctx) к своему LazyFrame, и запрос уходит считаться на кластер. Хоть петабайтный join, запущенный с ноутбука.
Распределённые движки обычно ощущаются как боль: куча микросервисов, тяжёлый JVM-рантайм, кластер поднимается минуты, а то и десятки минут. У Polars один бинарник и helm-чарт, кластер стартует за секунды. То есть реально можно поднимать отдельный кластер под каждый ETL-джоб и гасить после.
Плюс завезли две приятные штуки:
🔘Профайлинг запросов. Раньше движок был чёрным ящиком: пока запрос не закончился, ты не знал, что он делает. Теперь есть фронтенд и API, которые в реальном времени показывают, какая операция выполняется, сколько строк прошло через каждый узел и сколько данных шаффлится между воркерами. Причём работает и для одного узла, редкий шанс заглянуть внутрь движка на рантайме.
🔘 Data lineage через OpenLineage. Движок умеет слать события в любой коллектор (например, Marquez), так что видно, как и когда таблица создавалась и обновлялась.
@zen_of_pythonrequest.url он пересобирает строкой http://{host}{path}, где host берётся из заголовка Host. А Host контролирует клиент. И если приложение в middleware проверяет доступ так:
if request.url.path.startswith("/admin"):
return PlainTextResponse("Forbidden", status_code=403)
то достаточно дёрнуть /admin/potato с заголовком Host: example.com/? — роутер всё равно отдаст endpoint /admin/potato (он-то смотрит на сырой путь), а вот request.url станет http://example.com/?/admin/potato, и request.url.path схлопнется в просто /. Проверка не срабатывает, секрет утекает.
Что говорит сам мейнтейнер, и это самое интересное:
🔘баг живёт не во фреймворке самом по себе, а в паттерне приложения. Авторизацию вообще нельзя строить на пути, хосте или query — её ломают и трейлинг-слеши, и регистр, и percent-encoding. Host тут просто ещё один способ;
🔘если нужен реальный путь, бери request.scope["path"] — его никто из Host не пересобирает;
🔘чинится апгрейдом на Starlette 1.0.1, там Host наконец валидируется.
Но человеческая часть зашла даже сильнее технической. Исследователи сначала выкатили срок раскрытия в месяц и предложили созвон «через 2 или 5 дней», как будто у опенсорсника есть дежурная security-команда, а не вечера после основной работы. Под конец и вовсе предложили опубликовать advisory до того, как выйдет патч. Мейнтейнер прямо называет это ужасной практикой: открытое описание дыры без фикса оставляет всех уязвимыми, зато атакующие получают ровно ту же инструкцию.
Отдельно его задело, что под уязвимость подняли брендированный лендинг badhost.org с логотипом, именем и интернет-сканером. Маркетинг уязвимости: пока базы CVE не разъехались и Dependabot не прокликал алерты, человек узнаёт о дыре в своём проде из заголовка новости.
@zen_of_pythonlazy import json
lazy from pathlib import Path
print("старт") # json и pathlib ещё не загружены
data = json.loads('{"ok": true}') # здесь json наконец подгружается
Раньше ради быстрого старта тяжёлые импорты прятали внутрь функций. Теперь их можно держать наверху файла, как и положено, без платы за импорт при запуске. Есть и глобальные переключатели: флаг -X lazy_imports и переменная окружения, если хочется включить лень разом. И это не воскрешение отклонённого когда-то PEP 690, механизм тут другой и явный.
Второе приятное: встроенный frozendict (PEP 814). Неизменяемый и хешируемый словарь прямо в языке, без импортов. То же, чем frozenset является для set.
config = frozendict({"debug": True, "retries": 3})
# поменять значение уже нельзя, будет TypeError
Ещё одно: PEP 661 даёт штатный способ делать sentinel-значения вместо самодельных MISSING = object(). Теперь это нормальный механизм с человеческим repr и поддержкой в аннотациях типов.
Под капотом тоже движение: переработанный JIT даёт около 8-9% на Linux x86-64, интерпретатор с tail-call приехал и на Windows (там плюс 15-20%), появился стабильный ABI для free-threaded сборок.
Финальный 3.15 ждём осенью, но облик версии уже ясен. Лично я больше всего жду lazy import: сколько раз приходилось прятать импорты в функции ради быстрого CLI.
А вы ждёте 3.15 или пока сидите на чём-то постарше?
@zen_of_pythonsrc, тесты с print вместо pytest (хотя в CONTRIBUTING всё расписано), импорты вида from mylib import Foo, Bar, которых в коде и документации никогда не было. Сверху сабклассы от этих галлюцинированных типов, разобрать невозможно.
Отдельная деталь: у автора такого PR обычно куча форков других репозиториев, и везде он охотится за меткой good first issue. Похоже на сбор очков на GitHub, а не на желание реально закрыть задачу. Отсюда вопрос: стоит ли тратить силы на честное ревью и как закрыть PR, не отпугнув нормальных будущих контрибьюторов.
Что советуют бывалые мейнтейнеры:
🔘Просто закрыть и заблокировать. Самый частый ответ. К остальным это не враждебно: либо человек игнорит правила проекта, либо приносит код без ценности. И то и другое повод закрыть.
🔘 Завести метку вроде «doesn't follow contribution rules» и объяснить её в гайдлайнах. Тогда на закрытие уходит три клика, а если вернётся живой человек и поправит PR, это уже сигнал, что стоит посмотреть.
🔘 Поднять минимальный порог через CI. ruff, mypy или basedpyright, pytest с требованием покрытия, проверка докстрингов. Линтеры отсекают мусор автоматически, ещё до человеческого ревью.
🔘 Не закрывать вслепую каждый случай. Люди с неродным английским всё чаще прогоняют описание и доки через ИИ. Если контрибьюция небольшая, есть смысл быстро глянуть сам код.
Был и спор про AGENTS.md. Одни считают, что инструкции для агента поднимают качество PR. Другие, что само наличие файла как бы говорит «здесь рады ИИ-коду» и только притягивает слоп.
А вы как с этим справляетесь, если ведёте свои репозитории?
@zen_of_pythoncr_frame;
🔘починили множественное наследование для смешанных Python/C-extension типов, включая сценарии вокруг pybind11 и cpyext;
🔘PyPy3.11 теперь идёт со стандартной библиотекой CPython 3.11.15;
🔘дизассемблер стал ближе к CPython: интерпретатор перешёл на exception tables вместо отдельных opcodes. На скорость это пока не влияет.
Если вы уже используете PyPy, то обновление стоит поставить, API совместим с линейкой 7.3. Если только думаете попробовать — начните с прогона тестов на PyPy3.11 и проверки зависимостей.
PyPy лучше всего раскрывается на чистом Python-коде. В проектах, где основная нагрузка уходит в NumPy, pandas, torch или другие C-расширения, прирост может быть совсем другим.
@zen_of_pythonuv init
uv add fastapi
uv run app.py
uv sync --frozen
Риск с OpenAI тут скорее управленческий, а не технический. Важно смотреть на лицензию, телеметрию, темп релизов и то, останется ли core-разработка открытой. На практике же зависимости живут в стандартном pyproject.toml, а Python уже движется к стандартному lockfile через PEP 751 / pylock.toml, так что миграция с uv должна быть проще, чем с более закрытых форматов.
То есть вопрос скорее не про то, использовать ли uv, а о том как использовать его без религии и без лишней привязки к одному владельцу.
А вы как думаете? Продолжаем жить на uv, всё норм?TypedDict, ParamSpec, оператор type и прочее. Его аргумент: пора признать это формально и выбирать приоритеты по реальной боли пользователей. Опирался на Python Typing Survey 2025.
Дуглас Креагер из Astral (его слайд гласил «an OpenAI joint») показал девятистрочный пример, на котором все продакшен-чекеры (mypy, pyright, pyre, Pyrefly, ty) дают неверный ответ:
def choose[A](a1: A, a2: A) -> A:
return random.choice([a1, a2])
def partial[X, Y, Z](fn: Callable[[X, Y], Z], x: X) -> Callable[[Y], Z]: ...
p = partial(choose, None)
p(2) # все говорят: ошибка, 2 не None
p("hello") # то же самое
Прямой вызов choose(None, 2) работает корректно: A решается в None | Literal[2]. После применения partial система ломается. Креагер предлагает другую стратегию: тянуть весь набор констрейнтов как отложенный обобщённый тип, без преждевременной подстановки. ty переезжает на этот подход, внутри используется тернарная структура BDD (двоичные решающие диаграммы с третьим «неопределённым» ребром).
Коннер Нильсен из команды Pyrefly доложил результаты экспериментов с ИИ-агентами. Если код хорошо типизирован и type checker подключён к агенту через обёртку с циклом «думай, действуй, наблюдай»:
— Доля успешных решений на внутренних бенчмарках команды поднялась с 79,6 до 83,9 процента.
— На 21 процент меньше шагов до решения.
— На 14 процентов быстрее по полному времени работы.
На слабо типизированном коде из SWE-bench Verified эффекта почти нет. Type checker ловит ошибки в соседних с задачей файлах, и агент уходит чинить их вместо основной задачи. Наблюдение по моделям: Claude Sonnet 4.5 чинит каждую ошибку, GPT-5 codex игнорирует типы, пока обёртка насильно их не подсунет.
Ещё были доклады про intersection types (Jelle Zijlstra), PEP 827 от Vercel про conditional и mapped types по образцу TypeScript, tensor-shape типы в Pyrefly, и формализация подмножества Python в Lean 4. Полный обзор здесь: https://bernat.tech/posts/pycon-us-2026-typing-summit-recap/
@zen_of_python (теперь в VK и Max)concurrent.interpreters: публичный API для запуска нескольких полноценных интерпретаторов внутри одного процесса.
Это финал длинной истории. PEP 554 в 2017 году описал идею, PEP 684 в 2023 дал каждому интерпретатору собственный GIL, и PEP 734, принятый в июне 2025, превратил всё это в стандартный Python-модуль. До 3.14 функционал был доступен только через C API.
API ровно такой, какой ожидаешь:
import concurrent.interpreters as interpreters
interp = interpreters.create()
interp.exec('print("Hello from subinterp")')
interp.close()
Каждый интерпретатор изолирован: своя память, свой GIL, свой импорт-кеш. Простые типы передаются через специальный канал без копирования, сложные идут через сериализацию вроде pickle.
Что это даёт:
— Настоящая многозадачность в одном процессе без multiprocessing. Каждый интерпретатор едет на своём GIL и параллельно работает на отдельном ядре.
— Совместимость с asyncio. CPU-bound подзадачи можно гонять в субинтерпретаторах, а сетевой ввод-вывод оставить в основном цикле событий.
— Один процесс. Общие файловые дескрипторы, единое управление, без накладных расходов на fork и spawn.
У подхода одно главное ограничение: C-расширения. Стабильность под per-interpreter GIL не гарантирована, и многим библиотекам ещё предстоит дозревать. Чистый Python и библиотеки с поддержкой PEP 684 работают, остальные могут падать.
PEP 734 и free-threading решают одну задачу разными способами. Free-threading убирает GIL вообще: больше совместимости, меньше изоляции. Sub-interpreters сохраняют GIL на интерпретатор: меньше совместимости, больше изоляции. Похоже, в долгую Python поддержит оба пути.
Свежий разбор с примерами и архитектурой: https://alexeev-dev.bearblog.dev/running-multiple-interpreters-in-python-code-incredible-speed/
@zen_of_python (теперь в VK и Max)
¡Ya disponible! Investigación de Telegram 2025 — los principales insights del año 
