Отладка в Python: как искать ошибку через print
Автор: Казачкин Даниил Михайлович · Обновлено
Отладка начинается с воспроизводимого примера и ожидаемого результата. Диагностический print отвечает на конкретный вопрос: дошло ли выполнение до строки, какое значение получила…
Отладка начинается с воспроизводимого примера и ожидаемого результата. Диагностический print отвечает на конкретный вопрос: дошло ли выполнение до строки, какое значение получила переменная, сколько раз сработал цикл. Случайная россыпь сообщений только создаёт шум.
Поиск ошибки в накопителе
numbers = [2, 4, 6]
total = 0
for number in numbers:
total = number
print('step:', number, 'total:', total)
print('answer:', total)Трассировка покажет:
step: 2 total: 2
step: 4 total: 4
step: 6 total: 6
answer: 6Ожидалась сумма 12, но total совпадает с текущим элементом. Значит, ошибка находится в обновлении: нужно total += number. После исправления промежуточные суммы станут 2, 6 и 12.
Хорошая метка важнее лишней строки
Печать только числа непонятна, если переменных несколько. Добавляйте имя этапа и repr для строк, когда важны пробелы: print('raw:', repr(text)). Диагностику помещают непосредственно до и после подозрительного изменения.
Не оставляйте временные сообщения в итоговом выводе задачи. После исправления удалите их или используйте logging в настоящем приложении. Если программа падает, сначала прочитайте traceback снизу вверх: последняя строка называет тип, предыдущие показывают путь вызовов.
Локализация дефекта
Дана программа среднего значения [3, 5, 7], которая ошибочно делит сумму на len(numbers) - 1. Добавьте две диагностические строки, докажите, что сумма верна, а делитель нет, затем исправьте формулу. Проверьте список из одного элемента: он обнаружит деление на ноль в старой версии. Запишите, какой факт подтвердил каждый print.
Минимальный воспроизводимый пример
Возьмите ошибочную программу из нескольких этапов и сократите данные до наименьшего списка, на котором результат остаётся неверным. Удаляйте по одному действию, пока причина не станет локальной. Запишите ожидаемое, фактическое и последнюю подтверждённую правильную переменную. Затем добавьте ровно один диагностический print на границе между правильным и неправильным шагом. После исправления превратите минимальный пример в assert и удалите отладочный вывод. Такой процесс не зависит от размера проекта: он заменяет догадки последовательным сужением области поиска и оставляет регрессионную защиту.
Практикум: инвариант вместо потока случайных print
В программе поиска максимума намеренно обновите значение при неверном условии. Подготовьте вход, где ошибка заметна, и запишите ожидаемый максимум. Добавьте один диагностический вывод с индексом, текущим элементом и максимумом после итерации. Найдите первый шаг нарушения инварианта. После исправления замените наблюдение на assert maximum == max(prefix) только в учебной версии и проверьте несколько наборов. Удалите отладочный вывод из пользовательского результата, сохранив регрессионный тест.
Контрольная точка
Почему первая неверная переменная полезнее последнего неверного ответа? Она ограничивает участок кода между последним правильным состоянием и моментом нарушения.
Частые вопросы
Можно ли оставлять отладочные print в решении?
В отправляемом решении лишний вывод нарушает формат. Диагностические сообщения временно используют локально, а важный найденный случай сохраняют в тесте или assert, который не смешивается с ответом пользователя.