Последние посты

Zen of Python
23 сент., 11:00
Как __getitem__ превращает объект Python в итерируемыйДля цикла for объекту не всегда нужен __iter__. Если класс принимает целые индексы от 0, Python последовательно запрашивает элементы с индексами 0, 1, 2 и так далее. Получив IndexError, интерпретатор считает последовательность законченной.В примере из статьи арифметическая последовательность вычисляет элемент по формуле прямо в __getitem__: seq[3] возвращает 14, а тот же объект без дополнительного метода работает в цикле.Проверять поддержку целочисленных индексов заранее Python не станет. Поэтому обёртка над словарём выдаёт значения для ключей 0 и 1, а на ключе 2 падает с KeyError: эта ошибка не означает конец итерации. Механику и код можно посмотреть в статье Indexable iterables.


Zen of Python
23 сент., 08:01
Что меняет re.prefixmatch() в Python 3.15re.match() проверяет совпадение только в начале строки. Поэтому шаблон из шести цифр принимает и 345071-in-abbey-wood: подходящий префикс найден, а остаток не мешает успеху. Для проверки всей строки по-прежнему нужен fullmatch().В Python 3.15 появится prefixmatch(), точный синоним match(). Поведение не изменится, зато имя прямо сообщит, что проверяется лишь начало строки. Явное лучше неявного, даже когда речь всего лишь о названии метода.match() получит статус мягко устаревшего: предупреждений и планов удаления нет, существующий код продолжит работать. В новом коде под Python 3.15+ стоит выбирать prefixmatch() для проверки префикса, а fullmatch() для валидации значения целиком. Примеры и объяснение различий собраны в разборе Адама Джонсона.


Zen of Python
23 сент., 05:03
Pyodide разрешил публиковать WASM-колёса прямо в PyPIВ Pyodide 314.0 появилась прямая публикация пакетов для WebAssembly в PyPI. Раньше команда сама собирала и размещала пакеты, а теперь сопровождающие могут выпускать колёса для Pyodide так же, как для Linux, macOS и Windows.На момент публикации в Simon Willison’s Weblog новые теги pyemscripten использовали 28 пакетов.


Zen of Python
22 сент., 10:57
Как применять структурное сопоставление с образцом к деревьям в PythonСтруктурное сопоставление особенно выразительно на рекурсивных структурах. Автор моделирует булевы выражения датаклассами Var, And, Or и Not, а затем разбирает каждый тип веткой case.Вычислитель захватывает поля прямо в образце. Для переменной он берёт значение из словаря, для And и Or рекурсивно обходит дочерние выражения через all() и any(), для Not инвертирует результат. Общая ветка выбрасывает ошибку, если появился неизвестный подкласс: явное лучше неявного.Тот же приём автор переносит на форматированный вывод дерева. Получается компактный разбор того, как рекурсивно применять match к древовидным данным, не превращая обход в цепочку проверок типов.


Zen of Python
22 сент., 07:58
Почему в Python стоит подменять свой интерфейс, а не httpxЕсли бизнес-тест напрямую подменяет httpx.Client и httpx.Response, даже проверка пустого списка требует трёх вложенных моков. Тест повторяет чужой API, а его смысл тонет в настройке объектов.Автор предлагает поставить между бизнес-логикой и httpx тонкий DockerRegistryClient с методами get_repos() и get_repo_tags(). Бизнес-код работает с понятными операциями, тест подменяет один собственный объект, а смена HTTP-библиотеки не затрагивает эти проверки. Вложенность отступает перед явным интерфейсом: вполне по-питоновски.В статье «Don’t Mock What You Don’t Own» in 5 Minutes есть код до и после рефакторинга и границы эвристики. Обёртка не нужна, если сторонний API уже удобен; для редких сетевых ошибок прямой мок тоже может оказаться проще.


Zen of Python
22 сент., 05:00
Как точно типизировать args и kwargs в PythonЗапись args: tuple[int, str] выглядит как тип всего кортежа, но проверщик читает её иначе: каждый позиционный аргумент должен быть таким кортежем. У kwargs: dict[...] тип также относится к каждому именованному аргументу. Типизатор здесь не телепат.Для разнородных аргументов нужен Unpack: Unpack[tuple[int, str]] задаёт типы и порядок позиционных аргументов. Именованные описываются через TypedDict и Unpack[Kw], поэтому проверщик знает тип каждого ключа.В разборе аннотаций показаны и необязательные ключи: все сразу через total=False либо отдельные через NotRequired. До Python 3.12 эти типы берутся из typing_extensions. Подход пригодится обёрткам, которые передают аргументы функции с той же сигнатурой.


Zen of Python
21 сент., 10:59
Как точечно сравнивать скорость функций Python с tprofПрофилировщик помогает найти медленную функцию. Но после каждой правки снова измерять всю программу неудобно: отчёт приходится фильтровать, а профилировщик добавляет накладные расходы. tprof для Python 3.12+ следит только за выбранными функциями.В режиме сравнения одна функция становится базовой, а столбец delta показывает разницу. В примере sum(range(...)) выполнялся примерно на 62% быстрее цикла с накоплением. Запустить замер можно из командной строки, через контекстный менеджер или декоратор.В разборе Адам Джонсон показывает команды и Python API. tprof работает через sys.monitoring: регистрирует обработчики только для целевых функций, а время измеряет в C. Остальная программа не получает накладных расходов профилировщика.


Zen of Python
21 сент., 08:00
Как писать Python-скрипты, которые удобно запускать в пайплайнахВ разборе Bite code! собраны приёмы, которые оставляют однофайловый скрипт простым, но делают его предсказуемым для пользователя.Зависимости указываются в комментарии в начале файла: uv run создаёт временное виртуальное окружение, ставит пакеты и запускает скрипт. Секрет сначала ищется в переменной окружения с префиксом имени скрипта, затем в хранилище ключей ОС, а при отсутствии запрашивается через getpass и сохраняется после проверки.Результат операции отправляйте в stdout, ошибки и журнал в stderr: тогда конвейер получит только данные. Для пользователя оставляйте print(), диагностику включайте через logging по запросу, а переменные окружения перечисляйте в --help через argparse.


Zen of Python
21 сент., 05:02
Как упаковать Go-бинарник в wheel и подключить к PythonPyPI может раздавать не только Python-код. go-to-wheel собирает Go-программу в отдельные wheel-пакеты для Windows, macOS и Linux, а pip или uv выбирают сборку под ОС и архитектуру. Внутри пакета лежит бинарник; Python-точка входа находит его и запускает с переданными аргументами.Simon Willison показывает схему на sqlite-scanner: утилиту можно вызвать через uvx sqlite-scanner, а другой Python-пакет может объявить её зависимостью и запускать через subprocess. Пользователю не нужны Go и ручная сборка. PyPI немного выходит за должностную инструкцию, зато граница остаётся явной: Go отвечает за бинарник, Python — за установку и запуск.В статье Simon Willison’s Weblog разобраны структура wheel, команда сборки и пример плагина Datasette.


Zen of Python
20 сент., 10:56
Как collections.deque хранит элементы блокамиУ deque два конца, поэтому легко представить узел на каждый объект. В CPython звено списка хранит блок до 64 элементов. Соседние блоки связаны в обе стороны, а индексы указывают на первый и последний элементы.При append и pop внутри блока меняются индекс и ячейка. Новый блок нужен, лишь когда крайний заполнен; опустевший крайний блок отсоединяется. Поэтому интерпретатор реже выделяет и освобождает память, чем при отдельном узле на элемент, и deque работает быстрее.В разборе на mathspp.com эта механика собрана в упрощённой Python-реализации для Python 3.15. По коду можно проследить append и pop; левый край устроен симметрично.


Zen of Python
20 сент., 07:58
Что ускоряет django-msgspec в Django и где он расходится с jsondjango-msgspec заменяет компоненты Django и Django REST Framework аналогами на базе msgspec. Его написанные на C кодировщик и декодировщик JSON работают в несколько раз быстрее стандартной библиотеки. В пакете есть JsonResponse, тестовый клиент и json_script, а сериализаторы сессий и парсеры Django REST Framework подключаются через настройки.Совместимость близка к json, но не полна. Числовые ключи словаря превращаются в строки, большие целые сохраняются. При этом бесконечность кодируется как null, а ключи None и bool вызывают ошибку. Explicit is better than implicit: перед заменой стоит прогнать тесты на реальных данных.В разборе Адама Джонсона есть примеры настройки для ответов, сессий, dumpdata и loaddata, а также Django REST Framework.


Zen of Python
20 сент., 05:00
Почему миллион чисел в Python занимает 35 МБСписок из миллиона целых, которые помещаются в 64 бита, занимает в CPython около 35 МБ вместо ожидаемых 8 МБ. Из них 8 МБ уходят на указатели списка, ещё 28 МБ на числа: небольшой объект int весит 28 байт.В CPython каждое число является объектом. Кроме значения, у него есть счётчик ссылок и указатель на тип. На 64-битной системе эти служебные поля добавляют минимум 16 байт к каждому объекту. Явное лучше неявного, особенно в профиле памяти.Массив NumPy с типом uint64 хранит значения вместо ссылок на отдельные объекты Python. Поэтому миллион элементов занимает 8 МБ плюс память на импорт библиотеки. В разборе структуры объектов CPython есть замеры и код. Для больших числовых наборов проверьте NumPy до того, как 8 ГБ превратятся в 35 ГБ.


Zen of Python
19 сент., 13:10
Как перевести Python-сервер MCP с FastMCP на SDK 2.xСвежая установка зависимостей сломала сервер автора: в requirements.txt пакет mcp был без ограничения версии, поэтому pip подтянул ветку 2.x, где FastMCP переименовали в MCPServer. Код репозитория не менялся, а прежний импорт перестал работать. Explicit is better than implicit, особенно в файле зависимостей.Миграция начинается с замены импорта и имени класса. Декораторы @mcp.tool(), @mcp.resource() и тела инструментов в этом проекте остались прежними. Затем стоит закрепить mcp>=2,<3 и отдельно оставить httpx: SDK 2.x больше не устанавливает его как зависимость.В пошаговом разборе на DEV Community есть проверки синхронных обработчиков, переменных окружения и позиционных аргументов конструктора. Так пакет mcp обновляется внутри репозитория и не откатывается для остальных проектов в системном Python.
1,020Открыть в Telegram
Zen of Python
19 сент., 09:12
Как кэшировать методы чужого Python-клиентаЕсли библиотечный клиент нельзя менять, его методы можно переопределить с functools.lru_cache. Но кеш тогда включает self в ключ и удерживает экземпляр до вытеснения записи или очистки.Питоничнее обернуть уже связанный метод после создания объекта: кеш будет отдельным для каждого экземпляра, поэтому состояния клиентов не смешаются. Для множества методов автор перехватывает обращения через __getattribute__, кеширует метод при первом вызове и сохраняет обёртку в __dict__. Если объект создаёт фреймворк, эту механику можно вынести в прокси.В разборе Caching a lot of methods in Python показано, как вернуть прокси автодополнение через __dir__ и проверки isinstance() через wrapt.ObjectProxy. Для пары методов решение проще: заменить их кешированными прямо у готового объекта.death and gravityCaching a lot of methods in Python... in which you'll learn how to cache a lot of methods in Python, even for objects created by someone else. Did you know that, contrary to popular belief, Python programmers can have a little monkey patching as a treat?1,010Открыть в Telegram
Zen of Python
19 сент., 05:14
Где заканчивается ускорение NumPy и что выбрать дальшеВекторизация выполняет цикл низкоуровневым кодом. В тесте прибавление 17 к 100 млн элементов заняло 6,13 секунды для списка CPython и 0,07 секунды для массива NumPy.Предел виден, когда нужной операции нет в NumPy или вычисление создаёт промежуточный массив. np.abs(arr).mean() для массива на 1 ГБ выделяет ещё 1 ГБ под абсолютные значения. Цикл Python убирает копию, но возвращает расходы интерпретатора.В разборе Python⇒Speed решения разделены по задаче. PyPy ускоряет циклы по обычным объектам, но плохо сочетается с NumPy. Numba компилирует функции для NumPy. Cython, Rust, C и C++ позволяют собрать расширение заранее.«Явное лучше неявного» работает и для оптимизации: выбирайте инструмент по форме узкого места.


Zen of Python
18 сент., 16:59
Как подключать pytest-фикстуры без лишних аргументов тестаИногда фикстура нужна только ради побочного эффекта: например, перед тестом она подменяет os.environ. Если добавить её в параметры функции, pytest всё выполнит, но IDE подсветит неиспользуемый аргумент. Автор избегает autouse=True: по его оценке, так о тестах труднее рассуждать.Декоратор @pytest.mark.usefixtures с именем mock_env назначает фикстуру конкретному тесту. Pytest запускает mock_env, а в сигнатуре остаются только объекты, к которым код обращается напрямую. Декоратор принимает несколько имён фикстур, но помечать им другую фикстуру нельзя.В короткой статье с примером показано, как убрать серый неиспользуемый параметр и сохранить зависимость на виду. Явность победила, сигнатура тоже.
1,070Открыть в Telegram
Zen of Python
18 сент., 14:01
Как получать стабильный хеш Python-объектовВстроенный hash() для этого не подходит: хеши строк и bytes меняются между процессами, а списки, словари и изменяемые dataclass он не принимает. hashlib детерминирован, но ждёт байты. Значит, сначала объект надо привести к однозначному набору байтов.Автор разбирает, почему pickle не обещает одинаковый поток байтов, а str и repr могут терять значимые данные или включать адрес объекта. Решение строится на JSON: встроенные типы, datetime и dataclass приводятся к поддерживаемому представлению, неподдерживаемые значения вызывают ошибку, пустые и выбранные поля можно пропустить.В статье есть требования, промежуточные неудачные варианты и итоговый код без сторонних зависимостей. Подход пригодится, если хеш хранится дольше одного процесса или должен совпадать в разных реализациях Python.death and gravityDeterministic hashing of Python data objectsIn this article, you'll learn how to calculate deterministic hashes for arbitrary Python data objects, stable across interpreter versions and implementations.1,100Открыть в Telegram
Zen of Python
18 сент., 11:03
Когда namedtuple всё ещё лучше dataclassПосле появления dataclass именованный кортеж перестал быть универсальной заменой маленькому классу. Он всегда поддерживает индексацию и распаковку, поэтому новое поле ломает код с распаковкой, а публичный API рискует навсегда сохранить кортежный протокол.Это же поведение полезно, когда данные естественно упорядочены: строки БД, результаты разбора бинарного формата, пары заголовков HTTP. Если API уже возвращает обычный кортеж, namedtuple добавит имена полей, не сломав прежних потребителей. Можно и намеренно распаковывать все поля: забытый обработчик упадёт сразу после изменения структуры. Явное лучше неявного, как и договаривались.В разборе namedtuple и dataclass автор также сравнивает память и скорость. На миллионах экземпляров разница может стать заметной, а в большинстве программ она несущественна.death and gravitynamedtuple in a post-dataclasses worldnamedtuple has been around since forever, and over time, its convenience saw it used far outside its originally intended purpose. With dataclasses now covering part of those use cases, what should one use named tuples for? In this article, I address this…1,180Открыть в Telegram
Zen of Python
17 сент., 09:08
Как изолировать Pydantic Settings от окружения в pytestЕсли Settings создаётся при импорте пакета, он читает .env и переменные оболочки до запуска фикстуры pytest. Подмена os.environ запаздывает: значения уже сохранены в объекте, а тест зависит от окружения.Решение автора: фикстура сохраняет model_copy() объекта, сбрасывает поля к значениям по умолчанию из model_fields и применяет точечные переопределения. Неизвестные настройки и неверные типы она отклоняет, после yield восстанавливает исходное состояние.Подход пригодится, когда Settings уже живёт на уровне модуля. Явное снова лучше неявного. Код фикстуры и тесты со значениями по умолчанию и частичными переопределениями смотрите в разборе подмены Pydantic Settings.
1,190Открыть в Telegram
Zen of Python
17 сент., 06:10
переслано из @prog_stuff
Как устроен асинхронный веб-краулер на PythonОбстоятельная глава строит краулер с нуля: от корневого URL он скачивает страницы, извлекает новые ссылки и ставит их в очередь. Число одновременных запросов ограничивают, чтобы избыток конкуренции не снижал производительность.Разбор идёт от цикла событий с неблокирующими сокетами и колбэками к корутинам на генераторах, а затем к asyncio с асинхронной очередью. Переходы показывают, как избежать неуправляемых цепочек колбэков.Асинхронность не означает параллельные вычисления и не обязана быть быстрее потоков. Она подходит для множества медленных соединений с редкими событиями, где поток на каждый запрос расходует память и упирается в системные ограничения.В главе «A Web Crawler With asyncio Coroutines» из 500 Lines or Less код написан для Python 3.4. Читайте ради механики цикла событий; перед копированием сверяйте API с документацией.
