Zen of Python
18.8K subscribers
1.45K photos
202 videos
38 files
3.65K links
Полный Дзен Пайтона в одном канале

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Сайт: https://tprg.ru/site

Регистрация в перечне РКН: https://tprg.ru/xZOL
Download Telegram
Почему frozendict не замораживает вложенные объекты

В Python 3.15 появляется встроенный frozendict. В нём нельзя заменить значение по ключу или удалить запись. Но если значением служит список, сам список по-прежнему можно изменить через append.

Заморозка действует только на отображение. Поэтому frozendict с вложенным списком создаётся без ошибки, а вызов hash завершится TypeError. Для использования в ключе словаря или элементе множества все ключи и значения должны быть хешируемыми.

Есть ещё нюанс совместимости: frozendict не наследуется от dict. Проверка isinstance(value, dict) его отвергнет. Если функции достаточно чтения по ключам, контракт через collections.abc.Mapping принимает оба типа. Для вложенной структуры отдельно выбирайте подходящие контейнеры на каждом уровне.

#python #типизация
Как дождаться обработки очереди asyncio

Пустая очередь ещё не означает, что работа закончена: потребитель мог забрать элемент и продолжать его обработку. asyncio.Queue.join() ориентируется на число неподтверждённых задач, а не на количество элементов внутри очереди.

В схеме producer/consumer каждому успешному get() соответствует один task_done(). Подтверждение ставят после обработки, обычно в finally. Если подтверждать и неудачные задачи, join означает завершение учёта, а успех и повторную обработку нужно отслеживать отдельно.

maxsize ограничивает накопление: await put() ждёт, пока появится место. Для остановки потребителя можно отправить отдельный маркер, который тоже требует task_done(). Сам join работников не останавливает — после него нужно дождаться завершения их задач.

#python #asyncio
Как добавить MCP-сервер в Django-проект

django-mcpz позволяет зарегистрировать Python-функцию как MCP-инструмент и подключить сервер в urls.py как обычное представление. Функция получает HttpRequest, поэтому может использовать request.user и ORM проекта.

В примере Адама Джонсона инструмент считает заказы с необязательным фильтром статуса. Параметры и результат описаны через msgspec.Struct: библиотека строит JSON Schema и проверяет аргументы до вызова функции. Реализация рассчитана на обычное синхронное WSGI-развёртывание.

Аутентификация задаётся явно. Для клиентских инструментов есть отзываемые bearer-токены, для OAuth-клиентов — отдельное приложение авторизации. Аннотация read_only описывает инструмент для клиента; реальные права доступа к данным всё равно должен проверять сервер.

#python #django
Чего не проверяет runtime_checkable Protocol

Protocol позволяет описать небольшой интерфейс: например, метод send(destination, message). Класс может удовлетворять ему без наследования — статический анализатор проверяет совместимость структуры и сигнатур.

Декоратор runtime_checkable добавляет возможность isinstance, но такая проверка не валидирует сигнатуры методов. Наличие атрибута send не доказывает, что он принимает нужные аргументы или выполняет обещанное действие.

Поэтому проверка плагина требует нескольких уровней: типизация помогает проверить код, тест контракта — поведение адаптера, схема — внешние данные. Аннотация quantity: int сама по себе не отвергает отрицательное число, а корректная схема заказа не доказывает, что товар есть на складе.

#python #типизация
Как измерять время async-функции через декоратор

Обычная обёртка может вызвать async-функцию и получить объект корутины за микросекунды. Это ещё не время запроса: выполнение корутины начнётся позже, а исключение возникнет уже за пределами обёртки.

В разборе async-декораторов обёртка сама объявлена через async def. Она сохраняет время старта, выполняет return await fn(*args, **kwargs), а запись длительности помещает в finally.

Так измерение охватывает выполнение и очистку при ошибке или отмене. functools.wraps сохраняет метаданные и связь wrapped для интроспекции. Сам сборщик метрик тоже должен быть аккуратным: его ошибка в finally способна перекрыть исходное исключение, а блокирующий ввод-вывод задержит весь event loop.

#python #asyncio
Почему max_workers не ограничивает очередь задач

ThreadPoolExecutor(max_workers=8) разрешает одновременно выполнять восемь вызовов. Если сразу вызвать submit для миллиона записей, остальные будут ждать, удерживая Future, аргументы и связанные объекты в памяти.

Окно незавершённой работы ограничивает и подачу: отправить, например, 32 задачи, дождаться завершений через wait(..., FIRST_COMPLETED), забрать результаты и только затем добавить новые. Производитель перестаёт бесконечно убегать вперёд.

В Python 3.14 для обработки с сохранением входного порядка есть executor.map(..., buffersize=32). Ручная схема удобнее, когда результаты нужны по готовности. Ни одна из этих границ не задаёт число запросов в секунду: для внешнего API ограничение частоты рассчитывают отдельно.

#python #производительность
Как проверить, что мок заменил нужную зависимость

Если service.py делает from client import fetch, функция использует имя service.fetch. Патч client.fetch не заменит уже импортированную ссылку: тест может продолжить обращаться к настоящему клиенту.

Правило patch — заменять имя там, где тестируемый код его ищет. Для этого примера нужен patch("service.fetch", autospec=True). autospec проверяет совместимость вызова с сигнатурой зависимости и помогает поймать лишний аргумент.

Для async-зависимости важно проверить await: assert_called_once_with доказывает только вызов, а assert_awaited_once_with — ожидание корутины. Дополнительно проверяйте возвращённое значение или эффект работы сервиса. Один счётчик вызовов не показывает, что результат зависимости был использован правильно.

#python #тестирование