Zen of Python
Полный Дзен Пайтона в одном канале Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Сайт: https://tprg.ru/site Регистрация в перечне РКН: https://tprg.ru/xZOL
نمایش بیشتر📈 تحلیل کانال تلگرام Zen of Python
کانال Zen of Python (@zen_of_python) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 18 730 مشترک است و جایگاه 6 999 را در دسته فناوری و برنامهها و رتبه 35 209 را در منطقه روسيا دارد.
📊 شاخصهای مخاطب و پویایی
از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 18 730 مشترک جذب کرده است.
بر اساس آخرین دادهها در تاریخ 26 اکتبر, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -87 و در ۲۴ ساعت گذشته برابر -8 بوده و همچنان دسترسی گستردهای حفظ شده است.
- وضعیت تأیید: تأیید نشده
- نرخ تعامل (ER): میانگین تعامل مخاطب 6.18% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 4.24% واکنش نسبت به کل مشترکان کسب میکند.
- دسترسی پستها: هر پست به طور میانگین 1 158 بازدید دریافت میکند. در اولین روز معمولاً 795 بازدید جمعآوری میشود.
- واکنشها و تعامل: مخاطبان بهطور فعال حمایت میکنند؛ میانگین واکنش به هر پست 1 است.
- علایق موضوعی: محتوا بر موضوعات کلیدی مانند github, rust, pip, api, install تمرکز دارد.
📝 توضیح و سیاست محتوایی
نویسنده این فضا را محل بیان دیدگاههای شخصی توصیف میکند:
“Полный Дзен Пайтона в одном канале
Разместить рекламу: @tproger_sales_bot
Правила общения: https://tprg.ru/rules
Другие каналы: @tproger_channels
Сайт: https://tprg.ru/site
Регистрация в перечне РКН: https://tprg.ru/xZOL”
به لطف بهروزرسانیهای پرتکرار (آخرین داده در تاریخ 27 اکتبر, 2026)، کانال همواره بهروز و دارای دسترسی بالاست. تحلیلها نشان میدهد مخاطبان بهطور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامهها تبدیل کردهاند.
time-machine, замерил 3 августа, как две библиотеки подмены текущего времени ведут себя с ростом проекта. Прошлый такой замер он делал в 2021 году и получил разницу в 100–200 раз, теперь захотел показать не отношение, а саму зависимость от размера кодовой базы.
Стенд простой: генерируются пустые модули по 25 атрибутов, каждый десятый держит ссылки на date, datetime и time, как будто их импортировали по имени. Замеряется цикл включения и выключения подмены. Python 3.15, MacBook на M1, freezegun 1.5.5 и time-machine 3.3.0.
🔘 259 модулей, то есть почти голый интерпретатор: 1406,7 мкс против 1,5 мкс, разница в 940 раз;
🔘 1259 модулей, размер небольшого проекта на Django: разница в 2490 раз;
🔘 16 259 модулей, крупный проект с обвесом зависимостей: 40 971,3 мкс против неизменных 1,5 мкс, разница в 27 300 раз;
🔘 время freezegun укладывается в прямую: около 1,4 мс постоянных расходов плюс 2,5 мкс на каждый модуль;
🔘 в наборе из 2000 тестов с подменой времени это 82 секунды чистой замены ссылок против 3 миллисекунд;
🔘 причина в том, что freeze_time.start() обходит весь sys.modules и подменяет каждую найденную ссылку на настоящие функции; даже при попадании в кэш приходится перечислить и захешировать имена атрибутов всех модулей.
У обхода есть и содержательная плата, помимо скорости: он не находит ссылки в атрибутах классов, значениях по умолчанию, замыканиях и C-расширениях, и они продолжают отдавать настоящее время. Плюс подставленные объекты видны по типу, datetime.__name__ внутри подмены становится FakeDatetime, и код, который смотрит на типы, может повести себя иначе.
time-machine вместо обхода переписывает указатель ml_meth в структуре PyMethodDef у встроенных функций, читающих часы. Таких функций десять, и это ровно десять записей в память независимо от размера проекта.
Автор оговаривает, что модули в стенде синтетические, это types.ModuleType, положенные прямо в sys.modules, а не настоящие импорты, и что замеряется только цикл подмены, из нескольких прогонов берётся минимальное время.
Полная статья: https://adamj.eu/tech/2026/08/03/python-time-machine-o1-freezegun-on/
@zen_of_pythonThreadPoolExecutor заметно медленнее того же расчёта через ProcessPoolExecutor. Кумар Адитья из Quansight Labs описал 29 июля, как несколько месяцев вычищал причины этого в NumPy и самом CPython.
Нагрузка простая и типичная для ufunc: каждый работник берёт свой массив, гоняет по нему np.sin и np.cos в цикле и сворачивает результат. Общего изменяемого состояния между потоками нет, так что масштабироваться оно должно линейно. На деле до 18 потоков росло, а дальше резко деградировало: на 32 работниках 44 секунды против 6 у процессов. Профилирование через samply показало три класса проблем: конкуренция за блокировки, конкуренция за счётчики ссылок общих объектов и конкуренция в аллокаторе.
🔘 tracemalloc выключен по умолчанию, но всё равно брал глобальную блокировку на каждом выделении и освобождении памяти, просто чтобы проверить, включён ли он. Теперь проверка идёт атомарной операцией без блокировки;
🔘 кэш диспетчеризации ufunc, который сопоставляет типам аргументов конкретную реализацию, жил под std::shared_mutex. Записи в нём неизменяемы, поэтому чтение сделали полностью свободным от блокировок, мьютекс остался только на редкие вставки;
🔘 указатель на аллокатор памяти NumPy хранит в глобальном объекте PyCapsule. Без GIL каждое обращение к нему меняет счётчик ссылок атомарно, и кэш-линия со счётчиком начинает метаться между ядрами. Объект сделали бессмертным, то есть вообще без подсчёта ссылок;
🔘 ради этого в CPython появился публичный PyUnstable_SetImmortal: с 3.15 он доступен всем, на 3.14 его можно взять через pythoncapi-compat;
🔘 запись np.sin — это поиск атрибута в модуле, а специализация байткода для таких поисков не работала, если модуль определяет __getattr__. Каждый вызов уходил на медленный путь с захватом импортной блокировки;
🔘 массивы NumPy выделял системным malloc, который плохо переносит параллельные выделения, особенно на macOS. Сырой аллокатор CPython в сборке без GIL перевели на mimalloc, а NumPy переключили на этот сырой аллокатор.
После всех правок та же задача на 32 ядрах занимает около 1,5 секунды: примерно в 30 раз быстрее, чем было, и вчетверо быстрее варианта с процессами. Автор оговаривает, что замеры сделаны на одной 32-ядерной машине с Linux и на конкретной ufunc-нагрузке без общего состояния между потоками.
Пробовали сборку без GIL на своих задачах и во что упирались?
Полная статья: https://labs.quansight.org/blog/scaling-numpy-on-free-threaded-python
@zen_of_pythonlazy import json и lazy from json import dumps. Модуль не грузится, пока имя реально не тронули. Строго opt-in: меняется поведение только помеченных строк. Главные бенефициары — CLI-утилиты и тест-сьюты с тяжёлым деревом зависимостей.
— PEP 686, UTF-8 по умолчанию. Кодировка для I/O больше не зависит от системной локали. Откатить можно через PYTHONUTF8=0 или -X utf8=0 — и вот это стоит проверить заранее, если у вас Windows и legacy-файлы в cp1251.
— PEP 814, встроенный frozendict. Наконец-то неизменяемый словарь в ядре, а не в трёх конкурирующих пакетах на PyPI.
— PEP 798, распаковка в comprehensions. [*L for L in lists] для плоского списка, {**d for d in dicts} для слияния словарей — синтаксическая дыра, которая раздражала лет десять.
— PEP 799, семплирующий профайлер Tachyon прямо в стандартной библиотеке. Другой класс инструмента, чем cProfile: тот инструментирует каждый вызов и искажает картину на горячем коде, семплирующий периодически снимает стек и почти не мешает.
— JIT прибавил 6–7% среднего геометрического на x86-64 Linux и 12–13% на AArch64 macOS.
Плюс по мелочи: sentinel из PEP 661, TypedDict с типизированными extra-полями (PEP 728), TypeForm (PEP 747) и более внятные подсказки в AttributeError.
Полный список — в whatsnew, там же примеры кода и раздел с несовместимостями.
#python315 #cpythonENTER_TRACING() и LEAVE_TRACING();
🔘 в игрушечном замере медиана по 40 запускам составила 1,72 микросекунды без записи и 7,47 микросекунды с записью и JIT.
Автор оценивает накладные расходы максимум в 4,5x и сразу оговаривает, что сравнивать это с накладными расходами 900–1000x у PyPy некорректно.
Чем профилируете горячий Python-код сейчас и во сколько раз он от этого замедляется?
@zen_of_pythonhtml.parser и 836 мкс у html5lib. На плотном четырёхмегабайтном тексте escape отрабатывает за 4,98 мс против 12,7 мс у html.escape. Публикация от 18 июня обновлена 10 июля.
Скорость складывается из того, как обрабатываются байты. Обычный код ищет спецсимволы посимвольно, и процессор на каждом байте выполняет ветвление. Здесь байты обрабатываются пачками: SWAR складывает восемь байт в одно машинное слово и проверяет их арифметикой, SIMD делает то же самое сразу по шестнадцать байт одной инструкцией. Ветвлений в горячем цикле почти не остаётся.
🔘 длина результата сначала считается точно, потом выделяется одним куском и заполняется массовым копированием, вместо дописывания по мере разбора;
🔘 токенизатор сохраняет исходную ширину строки и компилируется в три варианта под UCS-1, UCS-2 и UCS-4;
🔘 чистые текстовые куски возвращаются как срезы без копирования, копия делается только когда она правда нужна;
🔘 переписывание css_path() с квадратичного перебора на индекс сократило пример со 112 мс до 0,9 мс;
🔘 список переиспользуемых обёрток ускорил find_all() с 1,9 до 1,4 мкс, но в сборке без GIL он отключён.
Автор оговаривает, что Callgrind считает инструкции, а не реальное время по часам, поэтому на него опираются только при сравнении вариантов. Корректность проверяется побайтовым сравнением с эталонными библиотеками, сборками с ASan и UBSan и фаззингом.
Что у вас парсит HTML в проде и сколько времени на это уходит?
@zen_of_pythonx = [] и x.append(1) pyright, Basedpyright и ty считают тип list[Unknown], а mypy, Pyrefly и Zuban выводят list[int].
Автор предупреждает, что процент прохождения тестов на соответствие не означает практической пользы: пункты в наборе неравноценны по важности, а инструменты в бете меняются быстро, так что цифры стареют.
Переезжали с mypy на что-то из нового поколения, и сколько чужих ошибок вылезло на неаннотированном коде?
@zen_of_pythonuv init теперь создаёт проект со сборочной конфигурацией
Astral выпустила uv 0.12.0 28 июля, первый крупный релиз после 0.11.0 в марте. Изменения касаются дефолтов инициализации, проверки хэшей и разбора архивов пакетов.
Раньше uv init создавал плоскую структуру без сборочной системы, и сборочную конфигурацию со структурой src приходилось добавлять отдельно. Теперь проект сразу пригоден для сборки.
🔘 uv init прописывает [build-system] на uv_build, кладёт код в src/<name> и добавляет точку входа в [project.scripts], прежнее поведение возвращает флаг --no-package;
🔘 отклоняются исходные дистрибутивы в форматах .tar.bz2 и .tar.xz, по PEP 625 допустим .tar.gz, старые .zip пока принимаются ради совместимости; заодно запрещены записи со сжатием bzip2 и LZMA внутри wheel;
🔘 wheel, способный перезаписать сам интерпретатор (файлы вида Python, python.py, Python.exe, записи в .data/scripts), больше не устанавливается;
🔘 режим предрелизов по умолчанию сменился с if-necessary-or-explicit на if-necessary, то есть предрелизная версия ставится только когда без неё зависимости не разрешаются;
🔘 директива --require-hashes внутри requirements.txt действительно включает проверку хэшей, а хэши только по MD5 отвергаются, нужен минимум SHA-256;
🔘 строже валидируется pylock.toml: обязателен массив packages, имя файла допустимо только вида pylock.toml или pylock.dev.toml, проверяется размер артефактов.
Авторы пишут, что большинству обновление не потребует правок. Исключение составляют проекты, где зафиксирована верхняя граница сборочного бэкенда: там нужно поднять до uv_build>=0.11.32,<0.13.
У вас в CI uv закреплён конкретной версией или подтягивается последний?
@zen_of_pythongc.collect() честно собирал циклический мусор, а RSS после него почти не опускался. Сакшам Шарма разобрал этот случай 8 июля.
Дело в разделении обязанностей. Сборщик мусора решает, какие объекты ещё достижимы, а аллокатор решает, вернутся ли освободившиеся страницы операционной системе. Освобождённый объект просто уходит обратно в кучу процесса, и пока в той же странице памяти лежит хоть один живой объект, отдать её ядру нельзя. У glibc malloc к этому добавляются кэш освобождённых блоков tcache и отдельные арены на каждый поток, так что многопоточный сервис держит несколько независимых запасов. В одном из примеров автора живые объекты занимали около 700 МБ при RSS около 2,8 ГБ.
🔘 признак, отличающий это от настоящей утечки: tracemalloc показывает стабильный объём, а RSS продолжает расти;
🔘 лечение обошлось без единой правки в коде Python, jemalloc подключается через LD_PRELOAD;
🔘 в продакшене к нему добавили PYTHONMALLOC=malloc и MALLOC_CONF=narenas:2,background_thread:true;
🔘 автор сообщает примерно о вдвое меньшем потреблении оперативной памяти после перехода;
🔘 проверить гипотезу можно и без замены аллокатора, через MALLOC_ARENA_MAX=2 и вызов malloc_trim(0).
Оговорка автора: malloc не универсально лучше встроенного pymalloc, на миллионах мелких объектов выигрыш может оказаться обратным, поэтому замену нужно мерить на своей нагрузке.
Приходилось ловить рост RSS при стабильном числе объектов, и чем в итоге объяснялось?
@zen_of_pythonnn.LinearCrossEntropyLoss объединяет последний линейный слой и функцию потерь, сокращая пиковый расход GPU-памяти до четырёх раз на моделях с большим словарём;
🔘 FlexAttention заработал на Apple Silicon;
🔘 torch.load() открывает safetensors без отдельной библиотеки;
🔘 появились Linux wheels для предварительных Python 3.15 и свободнопоточного 3.15t.
Заявленное ускорение FlexAttention примерно в 12 раз получено на конкретном разреженном шаблоне. Для плотного внимания SDPA остаётся быстрее. Сборки для Python 3.15 пока лежат в отдельном индексе PyTorch, а torch.compile с этой версией языка ещё не работает.
@zen_of_python--add-ignore. Он добавляет ruff:ignore к выбранной строке и отключает правило только в этом месте.
Новое preview-правило UP051 находит устаревшие декораторы из abc и предлагает замену. Команда ruff format получила --extend-exclude для дополнительных исключений. Проверка Jupyter Notebook теперь ловит синтаксические ошибки отдельно в каждой ячейке. В релиз также вошли оптимизации и исправления автофиксов.
@zen_of_python