Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Отладка приложений: debugpy, delve и культура брейкпоинтов

Отладка вместо print: debugpy, delve и пошаговое выполнение на ноутбуке

Как перестать отлаживать принтами: подключение debugpy и delve, брейкпоинты и условные точки, отладка в контейнере и по SSH, watch-выражения и типичные ошибки новичков.

Прямой ответ

Отладчик отвечает на вопросы, на которые print-отладка тратит десятки итераций: «какое состояние объекта в этой точке», «кто вызвал эту функцию», «как меняется переменная по шагам». Для Python стандарт — debugpy (движок отладки VS Code, работает с любым редактором), для Go — delve. Базовый навык осваивается за час: брейкпоинт, запуск под отладкой, пять действий — step over/into/out, continue, просмотр переменных. Продвинутый уровень, который экономит часы еженедельно: условные брейкпоинты, watch-выражения, отладка кода в контейнере и на удалённой машине, attach к живому процессу.

Python: от брейкпоинта до attach

Самый простой вход — VS Code: F5 с launch.json запускает модуль под debugpy без единой настройки в большинстве проектов. Три сценария, которые стоит освоить:

  1. Локальный запуск: "module": "pytest" с "args": ["tests/test_x.py"] — отладка конкретного теста; "program" — скрипт целиком.
  2. Встроенная точка в коде: строка breakpoint() (или import debugpy; debugpy.listen(5678); debugpy.wait_for_client()) — приложение останавливается и ждёт подключения редактора; незаменимо, когда запуск происходит не из редактора (CLI-утилита, воркер).
  3. Attach к запущенному процессу: debugpy --listen 5678 -m uvicorn app:app — сервер стартует с отладчиком, подключение в любой момент; тот же приём работает внутри контейнера (порт наружу через compose — стек по образцу статьи про Compose).

Для терминала без редактора есть pdb (стандартная библиотека): python -m pdb script.py, команды b/c/n/s/p — минималистично, но работает везде, включая SSH-сессию.

Go: delve и его особенности

Go отлаживается delve — и здесь важны две специфичные вещи. Первая: обычные инструменты сборки не подходят, delve компилирует бинарник сам (dlv debug / dlv test) с отладочной информацией; попытка прицепиться к оптимизированному release-бинарнику даёт «прыгающие» переменные — это не баг дебаггера, это оптимизации (-gcflags="all=-N -l" отключает их для отладочной сборки). Вторая: горутин много, и goroutines/grs в delve — обычные команды; отладка конкурентного кода начинается с выбора нужной горутины, а не с паники «всё прыгает». Интеграции: VS Code (Go-расширение ставит delve сам), Neovim через nvim-dap — настройка в статье про Neovim.

Брейкпоинты: приёмы, меняющие эффективность

Условные точки — останов только при order.id == 42 или len(items) > 100: вместо сотни прокруток цикла — одна остановка на нужной итерации. Logpoints (VS Code) — «брейкпоинт без остановки»: печатает выражение в консоль и продолжает; это print-отладка, которая не трогает код. Hit count — останов на каждой десятой срабатывании. Watch — выражения, пересчитываемые на каждой остановке (user.balance, len(queue)): наблюдение за инвариантом вместо ручного «p» десять раз. Call stack — ответ на «как мы сюда попали» за один клик; в print-отладке для этого печатают трейсы вручную.

Отладка в контейнере и по SSH

Два частых «не работает» решаются однотипно. Контейнер: дебаггер должен слушать внутри контейнера, а редактор подключается к проброшенному порту; исходники должны совпадать с кодом в образе (соберите образ из текущего рабочего дерева или монтируйте код volume'ом — иначе брейкпоинты «промахиваются» на строки). Удалённая машина: debugpy/delve запускаются на сервере с --listen, вы подключаетесь через SSH-туннель (ssh -L 5678:localhost:5678 server — проброс портов разбирается в статье про SSH-туннели линии); в VS Code это готовый сценарий Remote-SSH. В обоих случаях ключевое правило: версии кода и бинарника должны совпадать — половина «прыгающих брейкпоинтов» это рассинхрон.

Культура: когда отладчик, а когда другие инструменты

Отладчик силён в вопросах состояния и потока управления конкретной ситуации. Он не заменяет: профилирование (где медленно — сначала профиль, потом отладка узкого места; инструменты — в статье про профилирование Python), тесты (воспроизводимый баг оформляйте падающим тестом и отлаживайте его — фиксация регрессии бесплатна), и логи (поведение в проде за прошлую неделю дебаггером не восстановить). Зрелый порядок: воспроизвести в тесте → профиль/логи для сужения → отладчик для понимания причины → фикс и прогон теста.

Сценарии, где отладчик экономит часы

Три ситуации из практики, где разница с print-отладкой максимальна. Первая — «плавающий» баг, зависящий от состояния: условный брейкпоинт на подозрительном значении плюс watch на инвариант ловят момент расхождения за один прогон; print-подход требует угадать, что именно печатать, до того как поймёшь проблему. Вторая — чужой код (библиотека, фреймворк): step into погружается в исходники библиотеки и показывает, где ваши ожидания расходятся с её логикой — печатать внутри чужого кода банально негде без правок. Третья — «невозможное» состояние: исключение возникает в недрах стека, и точка останова на исключении (break on raise в debugpy, break -p в delve) переносит вас прямо в момент рождения проблемы, а не в место, где оно всплыло.

Отдельная категория — отладка данных: вместо чтения логов вы останавливаетесь и инспектируете живой объект — структуру словаря на три уровня вложенности, содержимое DataFrame, состояние ORM-сессии. В print-подходе каждая такая проверка — новый цикл «напечатал, перезапустил, прочитал»; в отладчике — одна остановка и серия выражений в консоли отладки. Именно этот переход от итераций по минуте к итерациям по секунде и есть главная практическая ценность навыка.

FAQ

Почему переменная показывает <optimized out>? Бинарник собран с оптимизациями — значение вынесено из доступных регистров/стека. Пересоберите с отладочными флагами (Go: -gcflags="all=-N -l"; Python не подвержен — там байткод).

Можно ли менять значения переменных на лету? Да: в debugpy — через Debug Console (x = 5), в delve — set var/config. Полезно для проверки гипотез «а что если»; в проде-подобных сценариях — осторожно.

Отладчик тормозит на большом проекте? Python-отладка замедляет выполнение в разы — это нормально, отладчик трассирует каждый кадр. Для «почему медленно в реальности» используйте профилировщик, а не дебаггер.

Как отлаживать multiprocessing-приложение? Дочерние процессы поднимают свои экземпляры debugpy ("subProcess": true в launch-конфиге); в delve каждый процесс отлаживается отдельно. Многопроцессная отладка — самый сложный сценарий, начинайте с однопоточного воспроизведения.

Источники: проекты debugpy и delve, документация VS Code Debugging (ссылки в шапке).