Программирование с ИИ
ENRU
4.5

Отладка печатью

когда её достаточно и как делать правильно

Что это

Вставить print и посмотреть, что в переменной, — самый простой способ отладки. Его принято считать несерьёзным, но для большинства задач он быстрее отладчика и не требует ничего настраивать.

Статья — о том, как печатать так, чтобы это помогало, и когда всё-таки нужен отладчик.

Как выглядит в коде

Плохо

print(data)
print(x)
print("тут")

Запустил, получил три непонятных вывода подряд и не знаешь, какой откуда.

Хорошо

print(f"[parse] items={len(items)} first={items[0] if items else None!r}")
print(f"[to_numbers] temp={it['temp']!r} type={type(it['temp']).__name__}")

Три приёма, которые делают печать полезной:

Метка. [parse] сразу говорит, откуда строка. При десятке печатей это экономит всё время.

!r вместо обычного вывода. repr показывает кавычки и невидимое. Разница решающая:

value = " 42 "
print(f"value={value}")      # value= 42
print(f"value={value!r}")    # value=' 42 '

Во втором случае сразу видно, что в строке пробелы, — а именно из-за них int() и падал.

Тип, а не только значение. '4' и 4 выглядят почти одинаково, а ведут себя по-разному. type(x).__name__ снимает вопрос.

Печать структуры

Для словарей и списков удобнее так:

import json
print(json.dumps(data, ensure_ascii=False, indent=2)[:500])

ensure_ascii=False — чтобы русский текст был читаемым, а не р. Срез [:500] — чтобы не залить терминал, если данных много.

Когда нужен отладчик

Печати хватает, пока ты знаешь, что печатать. Отладчик нужен, когда не знаешь:

ПечатьОтладчик
понятно, какие переменные смотретьнепонятно, что происходит вообще
один-два проходанужно пройти шаг за шагом
код запускается быстрокаждый запуск долгий
всё в своём кодеошибка где-то в чужой библиотеке

Самый дешёвый отладчик в Python — одна строка в нужном месте:

breakpoint()

Программа остановится, и ты окажешься в интерактивной оболочке, где можно смотреть любые переменные. c — продолжить, n — следующая строка, q — выйти.

Как сказать ИИ

Запрос
Я не понимаю, почему здесь получается пустой список.
Куда поставить две печати, чтобы это стало видно?
Код не меняй, только скажи места и что печатать.
Запрос
Добавь отладочную печать во все три функции: метка,
ключевые значения через !r и их типы. Потом я уберу.

И обязательный шаг в конце:

Запрос
Убери всю отладочную печать, которую мы добавляли.
Логирование через log.* не трогай.

На что смотреть

Печать осталась в коде. Классика: отладили, забыли убрать, оно уехало на сервер и теперь засоряет вывод. Перед коммитом — поиск по print( в диффе.

Печать вместо логирования в долгоживущем коде. В боте или на сервере print исчезает вместе с терминалом. Там нужен logging (статья 4.2).

Печатается не то место. Если вывод не меняется при явно разных входных данных, скорее всего, печать стоит не в той ветке кода — или до неё вообще не доходит.

Секреты в печати. print(config) вместе с токеном — и он в истории терминала, а то и в скриншоте, отправленном в чат.

Шпаргалка

  • Метка в начале строки: [parse] ....

  • Всегда !r — видно пробелы, кавычки, None.

  • Печатай тип, а не только значение.

  • Словари — через json.dumps(..., ensure_ascii=False) и срез.

  • Не знаешь, что смотреть, — breakpoint().

  • Перед коммитом проверь дифф на оставшиеся print(.