python_practics
前往频道在 Telegram
Python - обучающие материалы, полезные советы и статьи. Админ, сотрудничество, реклама: @seniorFrontPromo, @maria_seniorfront Купить рекламу: https://telega.in/c/python_practics
显示更多5 117
订阅者
+624 小时
-127 天
-3330 天
帖子存档
5 117
RuStore Mobile GameDev Conf — 2 ноября
Разработчики, издатели, маркетологи, лидеры игровой и мобильной индустрии на одной площадке. Кейсы, инструменты продвижения и монетизации, тренды рынка и премия RuStore 2026.
Москва + онлайн. Участие бесплатное, по регистрации.
Зарегистрироваться
#реклама 16+
rustore.ru
О рекламодателе
5 117
⏰ Напоминание пришло на три часа позже, и Python не выдал ни одной ошибки
Бот для автосервиса писал клиенту за час до визита. Локально всё работало, а в Docker на VPS сообщения стали опаздывать ровно на три часа.
Виноваты «наивные» datetime, то есть даты без часового пояса. Напоминание хранилось как «17:00» неизвестно по каким часам. А
datetime.now() берёт время системы: на ноутбуке Москва, в контейнере UTC. Вот и вышло 17:00 по UTC, или 20:00 по Москве.
Правило простое: берите datetime.now(timezone.utc), храните в базе UTC, а в часы пользователя переводите только на входе и выходе. Сравнить наивную дату с датой с поясом Python не даст, так что забытое место всплывёт исключением.
Замена на utcnow() не спасает: он тоже возвращает наивный объект, а с Python 3.12 ещё и помечен устаревшим.
А ещё в статье: почему ежедневная сводка после перевода часов съезжает на час.
👍 - если было полезно
@python_practics5 117
Зарабатывайте на установках Яндекс Браузера
Партнёрская программа для сервисных центров, магазинов компьютерной техники, сайтов для скачивания файлов и авторов статей.
Вы можете предлагать его своим клиентам и аудитории — и зарабатывать на новых установках.
Выплаты до 500₽ за каждую установку Яндекс Браузера.
Подать заявку
#реклама 0+
partner.browser.yandex.ru
О рекламодателе
5 117
🔍 Первый запрос в тесте FastAPI проходит, второй падает
TestClient из FastAPI не поднимает сервер. Он вызывает приложение как функцию в фоновом потоке со своим событийным циклом. Без with на каждый запрос заводится новый цикл.
Пул asyncpg, созданный лениво при первом запросе, привязан к его циклу. Цикл закрывается после ответа, и второй запрос падает с «another operation is in progress», хотя другой операции нет. Под uvicorn цикл один на процесс, и ошибки нет.
Лечится так: пулы создаются в lifespan, а клиент живёт в with на всю сессию тестов:
import pytest
from fastapi.testclient import TestClient
from app import app
@pytest.fixture(scope="session")
def client():
with TestClient(app) as c:
yield c
Но если пул создать в асинхронной фикстуре pytest-asyncio, не спасёт и with: у фикстуры свой цикл.
В статье ещё три расхождения TestClient с настоящим сервером, включая 500, которую тест не видит.
👍 - если было полезно
@python_practics5 117
🤖Podlodka Backend Crew: AI в бэкенд-задачах
Демо с AI чаще всего выглядят одинаково: агент за десять минут пишет сервис с нуля.
Вот только в работе бэкендера всё сложнее: легаси, рискованные миграции, неработающие тесты и ревью, которое становится бутылочным горлышком.
🗓 С 26 по 30 октября в сезоне Podlodka Backend Crew «AI в бэкенд-задачах» участники:
• Научатся передавать агенту инженерные стандарты и правила, чтобы он писал так, как нужно, а не как получится
• Соберут ревью, где несколько моделей независимо проверяют изменения, а финальное решение остаётся за человеком
• Посмотрят, куда переезжает сложность миграции легаси, когда код пишет агент
• Выяснят, где ломается мечта отдать миграцию агенту целиком
• Разберут, какие антипаттерны тестов агенты уже успели перенять от разработчиков.
Формат — пять дней живых Zoom-сессий утром и вечером, закрытое сообщество в Telegram и общение со спикерами.
Будет много интерактива и практики. Базовый ликбез оставят за бортом — этот сезон для тех, кто уже пробует AI в реальных проектах. Присоединяйтесь с 26 октября!
🔗 Билеты и программа: https://podlodka.io/becrew
5 117
😄 Клиент нажал /cancel, а менеджеру пришла заявка от человека по имени «/cancel»
Такое случилось у разработчика Telegram-ботов на aiogram 3, библиотеке для Python. Бот вёл анкету по шагам: сначала ждал имя, потом телефон.
В aiogram 3 обработчики внутри роутера проверяются в порядке регистрации. Хендлер шага с именем ждал любой текст, а команда тоже текст. Он сработал первым, и до обработчика /cancel дело не дошло.
Лечится так: служебные команды живут в отдельном роутере, который подключается раньше остальных. А в шагах со свободным текстом команды ещё и отсекаются фильтром. Это страховка на случай, если кто-то потом добавит команду не в тот роутер:
@router.message(Order.name, F.text, ~F.text.startswith("/"))
В статье ещё две такие грабли, и одна из них теряет недописанные анкеты при каждом перезапуске бота.
👍 - если было полезно
@python_practics5 117
💳 Как не выдать товар дважды, если об оплате сообщили двое
В Казахстане оплату в Telegram часто принимают так: клиент переводит на Kaspi и шлёт скриншот, а человек ищет платёж глазами.
Автор разбора собрал бота на aiogram 3, который сам выставляет QR Kaspi Pay и выдаёт товар. Счета идут через сервис Aitole, в разработке которого автор участвует.
Об оплате бот узнаёт двумя путями: по вебхуку за секунды и опросом статуса раз в минуту, если вебхук потерялся. Сработать могут оба сразу, поэтому paid ставится одним условным апдейтом:
UPDATE orders SET status = 'paid', paid_at = now()
WHERE op_id = $1 AND status = 'pending'
RETURNING chat_id;
Строку обновит только один из них, он и выдаст товар.
Есть и ловушка. У Kaspi одна активная сессия на номер, и если войти в Kaspi Pay под номером, отданным сервису, бот продолжит отвечать, но деньги принимать перестанет.
Подпись вебхука, Idempotency-Key и песочница разобраны в статье, весь бот около 200 строк.
👍 - если было полезно
@python_practics5 117
Бесплатный 14-дневный онлайн-курс по дизайну интерьеров
Давно хочешь работать в творческой сфере и иметь доход от 100 тыс/мес? Тебе не нужно уметь рисовать или прямо сейчас принимать решение. Просто приходи и попробуй! Вдруг понравится создавать уютные интерьеры и ты найдешь в этом себя.
Регистрируйся на практический курс по дизайну интерьера с личным наставником. Осталось 7 мест!⚡
Зарегистрироваться
#реклама 16+
diskill-traning.ru
О рекламодателе
5 117
🔍 Как подсмотреть сообщения RabbitMQ, не мешая рабочей цепочке
Ручные тесты интеграций с брокером RabbitMQ часто проводят через веб-интерфейс. Но если очередей несколько, каждую приходится смотреть отдельно.
Есть подход «подписка как шпион». Скрипт на Python-библиотеке pika создаёт тестовую очередь и привязывает её к тому же обменнику (exchange) с тем же ключом маршрутизации, что и рабочую. Сообщения начинают дублироваться и в неё.
Рабочие обработчики (консьюмеры) выключать не нужно. Скрипт просто печатает в консоль exchange, routing_key и тело каждого сообщения.
ch.queue_declare(queue=DEBUG_QUEUE_NAME)
ch.queue_bind(exchange=EXCHANGE_NAME, queue=DEBUG_QUEUE_NAME, routing_key=ROUTING_KEY)
Одно условие: имена обменников и ключи нужно знать заранее и вписать в параметры скрипта.
В оригинале есть вариант сразу для нескольких обменников и проверка на RabbitMQ, поднятом локально в Docker.
👍 - если было полезно
@python_practics5 117
⚡️ В сети начали массово сливать IT-курсы и книги известных онлайн школ
Вот отсортированная база с тонной материала (постепенно пополняется):
(363 видео, 87 книги) — Python
(117 видео, 53 книги) — ВАЙБКОД
(174 видео, 91 книги) — DevOps
(415 видео, 68 книги) — Frontend
(137 видео, 93 книги) — DS/ML
(143 видео, 33 книги) — ИБ/Хакинг
(352 видео, 89 книги) — С/С++/C
(343 видео, 87 книги) — Java/QA
(176 видео, 32 книги) — Git/Linux
(167 видео, 53 книги) — PHP/1С
(227 видео, 83 книги) — SQL/БД
(114 видео, 77 книги) — Сисадмин
(107 видео, 43 книги) — BA/SA
(181 видео, 32 книги) — Go/Rust
(167 видео, 43 книги) — Kotlin/Swift
(112 видео, 24 книги) — Flutter
(113 видео, 82 книги) — GameDev
(183 видео, 37 книги) — Дизайн
(136 видео, 33 книги) — PM/HR
Скачивать ничего не нужно — все выложили в Telegram
5 117
🐍 В Python 3.15 список списков можно расплющить одной звёздочкой
Раньше, чтобы собрать вложенные списки в один плоский, писали comprehension с двумя for: внешний перебирает подсписки, внутренний их элементы.
Теперь звёздочка * работает прямо внутри comprehension. Она высыпает каждый подсписок в результат целиком:
nested = [[0, 1, 2], [3, 4], [], [5, 6, 7]]
flattened = [*sublist for sublist in nested]
print(flattened) # [0, 1, 2, 3, 4, 5, 6, 7]
Как понять, где это пригодится? Если видите цикл for с list.extend или set.update внутри, это знак, что его можно свернуть в такую запись. Так же звёздочка работает в set comprehension и генераторных выражениях.
Со словарями есть нюанс: там нужны две звёздочки **, а при совпадении ключей остаётся значение из последнего словаря.
А как так упрощается реальный код из shutil и dataclasses в стандартной библиотеке, автор показывает на живых примерах.
👍 - если было полезно
@python_practics5 117
🐍 self в Python не магия, а обычный первый аргумент
В блоге mathspp ООП в Python выводят из обычных функций, шаг за шагом. Сначала есть просто функции вроде
author_name(author), которые получают данные автора и что-то с ними делают.
Потом эти функции переносят в class Author. На этом шаге класс ничего нового не умеет. Он просто общая «папка» для функций про авторов, и вызов выглядит так: Author.name(charles).
Дальше Python разрешает писать короче: charles.name(). Объект сам подставляется первым аргументом. Поэтому в определении функции первым параметром стоит self, а при вызове его не передают.
Отсюда и частая путаница: функция объявлена с четырьмя параметрами, а вызывается с тремя. Лишний аргумент просто подставляет Python.
В статье весь путь от россыпи функций до __init__ и self пройден на примере каталога книг Диккенса, и после него классы перестают казаться чёрным ящиком.
👍 - если было полезно
@python_practics5 117
⏱ Таймаут в секунду, а вызов ждал 1124 мс
Возьмём асинхронный HTTP-клиент на Python. Семафор ограничивает число одновременных обращений к сервису, а asyncio.timeout_at даёт всей операции секунду. Кажется логичным сначала взять слот, а потом засечь время.
Но тогда ожидание в очереди к семафору в эту секунду не входит. На тестовом стенде автора слот был занят 1100 мс, а сервер отвечал за 20 мс. Медиана вышла 1124 мс, и таймаут ни разу не сработал.
Срок нужно считать до очереди:
deadline = loop.time() + 1.0
async with asyncio.timeout_at(deadline):
async with semaphore:
return await retry_cycle()
Теперь ожидание обрывается на 1001 мс, и запрос на сервер даже не уходит.
Учтите: deadline лишь прекращает ожидание на стороне клиента. Если запрос уже ушёл, сервер может доделать работу, и её никто не откатит.
Дальше в статье тот же разбор для ретраев, пула соединений aiohttp и медленного чтения тела ответа.
👍 - если было полезно
@python_practics5 117
АЙТИШНИКИ БЕСПЛАТНОЕ ОБУЧЕНИЕ
Проект «Terminal» стал крупнейшей библиотекой бесплатного образования. В одном канале собраны курсы, книги, полезные инструменты и практические тренажёры для всех разработчиков:
• Практические курсы и задания
• Книги и статьи известных авторов
• Полезные инструменты и ресурсы
• IT-новости и инсайды
Обучение по всем направлениям: SQL, Python, ML, Frontend, PHP, C++, Go, Git, Linux, QA, Java, Vibe-coding, InfoSec и др.
⌨️ подписаться
5 117
🔴В 2025 году Россияне заработали 5,3 млрд рублей на арбитраже криптовалют
По данным Минфин 32% граждан покинули своё место работы поскольку уже в первый месяц смогли заработать 250 000 рублей, а через 2-3 месяца с легкостью вышли на семизначные числа.
Самое смешное, что лишь 8% россиян что-то слышали об этой профессии хотя все инструкции бесплатно лежат на канале Арбитраж Криптовалют
Там объясняют, как имея телефон и доступ в интернет заработать свои первые $3000. Причём разжёвывают так доступно, что поймёт даже ребенок. Кстати, на канале сегодня вышла новая рабочая связка!
Ссылка для входа — https://t.me/+GY-3aS-FN5c0Yjhi
5 117
🧪 Почему тест цены падает, когда совы не летят?
Принцип единственной ответственности (S в SOLID) звучит так: у класса должна быть одна причина меняться. Стивен Группетта разбирает его на примере лавки зелий на Python.
Там метод
sell() делает всё. Он ищет рецепт, списывает ингредиенты, считает скидку, печатает этикетку, записывает продажу и шлёт клиенту сову. Совы бастуют, и тест цены падает с OwlUnavailable. А ингредиенты уже списаны, продажа записана.
Каждую задачу выносят в свой класс: Inventory, PriceCalculator, Notifier и другие. PotionShop только координирует продажу, а цену можно проверить без склада и сов.
При этом речь не про «один метод на класс». Выносить стоит то, что меняется по другой причине (скидки, дизайн этикеток, уведомления) или упрощает важный тест.
В статье лавку перестраивают шаг за шагом, с кодом и выводом на каждом этапе.
👍 - если было полезно
@python_practics5 117
🚀 В Python 3.15 модуль можно загружать, только когда он понадобился
Обычно import сразу выполняет модуль, а тот по цепочке импортирует свои зависимости. Если среди них есть медленные (скажем, с сетевой аутентификацией), CLI будет ждать их даже ради
my_cli --help.
Для этого появилось ключевое слово lazy. Такой модуль загрузится при первом обращении к нему, а не на строке импорта:
import json
lazy import math
lazy from pathlib import Path
Здесь json загрузится сразу, а math и pathlib только когда понадобятся.
Подвох в том, что ошибки тоже откладываются. Опечатку в lazy from json import load_json Python заметит не на строке импорта, а там, где load_json впервые вызовут.
А ещё в статье есть способ объявить ленивые импорты так, чтобы код без изменений запускался и на старых версиях Python.
👍 - если было полезно
@python_practics5 117
🔗 Как открыть ссылки на сайт прямо в его приложении
Если у сайта есть приложение для iOS или Android, ссылки на сайт могут открываться в нём. У Apple это Universal Links, у Android App Links.
Но приложение не может само объявить чужие ссылки своими, иначе их перехватило бы любое вредоносное приложение. Поэтому связь двусторонняя: приложение называет свои домены, а домен подтверждает, каким приложениям доверяет.
Со стороны сайта это JSON-файл:
/.well-known/apple-app-site-association для Apple и /.well-known/assetlinks.json для Android. В Django их отдают два маленьких view: по HTTPS, ответ 200 без редиректов, content-type application/json.
Подвох в том, что ошибка в файле ничем себя не выдаёт. Ссылки просто открываются в браузере, и нигде нет ни одного сообщения.
Готовые view, тесты к ним и команды, чтобы после деплоя проверить, что видят Apple и Google, собраны в оригинале.
👍 - если было полезно
@python_practics5 117
🎨 Код в Word можно подсветить текстом, а не вставлять картинкой
Когда .docx собирают из Python, код проще всего вставить скриншотом. Но такой код не скопировать, не найти через Ctrl+F и не поменять ему шрифт.
На Хабре разобрали модуль примерно на сто строк, который вставляет код текстом с подсветкой. Библиотека Pygments режет код на токены и для каждого сообщает цвет, жирность и курсив. А абзац в python-docx состоит из фрагментов (runs) со своим форматированием. Каждый токен просто становится фрагментом.
Соседние токены с одинаковым стилем склеиваются, а весь листинг остаётся одним абзацем. В замере на 30 листингах сборка заняла 0,6 с против 4,1 с с картинками.
Рамку и заливку пришлось задавать прямо в XML. Word тут строже LibreOffice: при неверном порядке тегов он может не открыть файл, так что проверять результат стоит именно в Word.
А ещё в статье есть подпись «Листинг N», которая нумеруется сама.
👍 - если было полезно
@python_practics
5 117
🚀 Кэш для uvx в GitHub Actions без файла зависимостей
Команда
uvx из менеджера пакетов uv запускает Python-утилиту одной строкой. Но в GitHub Actions пакет при каждом запуске заново качается с PyPI. Кэш обычно привязывают к хэшу requirements.txt, а заводить такой файл ради пары утилит не хочется.
Выручает переменная UV_EXCLUDE_NEWER. С ней uv ставит самые свежие версии пакетов на указанную дату. Пока дата та же, версии не меняются.
Эту же дату Саймон Уиллисон добавляет в ключ кэша через cache-suffix в astral-sh/setup-uv. Чтобы обновить утилиты и сбросить кэш, достаточно поменять дату в одном месте.
Учтите одно: когда кэш нашёлся, он включает UV_OFFLINE=1, и uv не ходит в сеть. Поэтому новая утилита, добавленная без смены даты, упадёт с ошибкой.
Весь рецепт умещается в один короткий workflow.
👍 - если было полезно
@python_practics