Ошибки в Python - 7 шагов для поиска ошибок в коде Python

Представьте себе такую ситуацию: в пятницу в обед вы получаете уведомление о том, что клиент обнаружил ошибку в вашем программном обеспечении. После того, как вы преодолели свое первоначальное недоверие, вы связываетесь с DevOps, чтобы узнать, что творится с логами для вашего приложения, потому что вы помните, что получили уведомление о том, что они были перемещены.

Оказывается, они находятся там, куда вы не можете добраться, но они находятся в процессе перемещения в веб-приложение, поэтому у вас будет подходящий инструмент для их чтения и поиска, но, конечно, он еще не закончен. Все будет готов лишь через пару дней. Это практически нереальная ситуация, верно? К сожалению, нет. Логи или сообщения логов часто невозможно найти в тот самый момент, когда они больше всего нужны. Прежде чем мы начнем отслеживать ошибки, следует сделать публичное объявление: проверьте ваши логи, чтобы убедиться, что они на месте и регулярно записывают то, что, по вашему мнению, они должны регистрировать. Удивительно, как все эти вещи куда-то исчезают, когда ты за ними не смотришь.

Итак, вы нашли логи или проверили сообщение клиента, который действительно обнаружил ошибку. Может быть, вы даже думаете, что знаете, где эта самая ошибка спряталась.

Вы немедленно открываете файл, который, по вашему мнению, может быть проблемой, и начинаете в нем ковыряться.

1. Не трогайте пока еще свой код

Взгляните на проблемное место и, возможно, даже выдвиньте гипотезу. Но прежде чем вы начнете разбираться в коде, возьмите тот вызов, который создает ошибку, и превратите его в тест. Это будет интеграционный тест, потому что (хотя у вас уже могут быть догадки) вы еще не знаете точно, в чем проблема.

Убедитесь, что этот тест не пройден. Это важно, потому что иногда тест, который вы делаете, не имитирует прерванный вызов; это особенно верно, если вы используете веб-интерфейс или другой фреймворк, который может запутать тесты. Многие вещи могут храниться в переменных, и, к сожалению, из самого теста не всегда очевидно, какой вызов вы в нем делаете.

2. Напишите неудачный тест

Теперь, когда у вас есть провальный тест или, возможно, тест с ошибкой, пришло время для устранения неполадок. Но прежде чем сделать это, давайте сделаем обзор стека, так как это облегчает поиск неисправностей.

Стек состоит из всех задач, которые вы начали, но не завершили. Итак, если вы будете печь торт и добавлять муку в тесто, то ваш стек будет:

  • Сделать торт;
  • Сделать тесто;
  • Добавить муку.

Вы начали готовить торт, начали готовить жидкое тесто и добавляли муку. Смазывания сковороды нет в списке, так как вы уже закончили это, а приготовления глазури нет в списке, потому что вы еще этого не начали.

Если вы не совсем разобрались в стеке, я настоятельно рекомендую попробовать Python Tutor, где вы можете наблюдать за стеком при выполнении строк кода.

Теперь, если с вашей программой на Python что-то пойдет не так, интерпретатор услужливо выведет для вас стек. Это означает, что независимо от того, что программа делала в данный момент, станет очевидно, что что-то пошло не так, как надо.

3. Всегда проверяйте дно стека в первую очередь

И не только дно стека, где вы можете увидеть, какая именно ошибка у вас произошла, но и последнюю строку стека, где вы чаще всего можете найти проблему. Если нижняя часть не помогает, и ваш код не проверялся уже какое-то время, удивительно, насколько полезным может быть его запуск. Я рекомендую pylint или flake8. Чаще всего именно они указывают на то, где есть ошибка, которую я пропустил.

Если ошибка является чем-то неясным, вашим следующим шагом может стать просто Google. Вам повезет больше, если вы не включите информацию, относящуюся только к вашему коду, например, имя переменных, файлов и т. д. Если вы используете Python 3, полезно включить 3 в поисковый запрос; в противном случае решения Python 2 имеют тенденцию доминировать в топе.

Когда-то разработчикам приходилось устранять неполадки без помощи поисковой системы. Это было темное время. Так что воспользуйтесь всеми доступными вам инструментами.

К сожалению, иногда проблема возникала раньше и стала очевидной только во время выполнения строки в нижней части стека.

Пришло время искать стек. Скорее всего, проблема заключается в том, что проблема в вашем коде, а не в ядре Python или даже в сторонних пакетах, поэтому сначала сканируйте стек, ища строки в вашем коде. Кроме того, обычно гораздо проще установить точку прерывания в вашем собственном коде. Вставьте ее в свой код немного дальше вверх по стеку и посмотрите вокруг, чтобы увидеть, что все выглядит, как и должно.

Затем воспользуйтесь помощью Pdb (the Python Debugger).

Найдите в своем коде место, в котором по вашему мнению должен появиться вызов. Вы должны быть в состоянии найти хотя бы одно такое место. Воткните туда pdb.

Отступление

Почему не печатное выражение? Я привык зависеть от печатных выражений. Они все еще иногда пригождаются. Но как только я начал работать со сложными кодами, особенно с сетевыми вызовами, печать стала слишком медленной. Я закончил с печатными заявлениями повсюду, я потерял след, где они были и почему, и все только усложнилось. Но есть более важная причина использовать pdb. Допустим, вы поместили заявление для печати и обнаружили, что что-то не так – и, должно быть, раньше пошло не так. Но, глядя на функцию, в которую вы помещаете оператор print, вы не представляете, как вы туда попали. Просмотр кода – отличный способ увидеть, куда вы идете, но он ужасен для изучения того, где вы были. И да, я сделал обзор своей базы кода, ища, где вызывается функция, но это может быть слишком утомительным занятием и не сильно сузить границы поиска с помощью популярной функции. Pdb может быть крайне полезным.

Вы следуете моему совету, вставляете pdb-break и запускаете тест. И он проваливается и снова терпит неудачу, без перерыва вообще. Оставьте свою точку прерывания и запустите тест уже в вашем наборе тестов, который делает что-то очень похожее на неудачный тест. Если у вас есть приличный набор тестов, вы сможете найти тест, который соответствует тому коду, который, по вашему мнению, должен пройти ваш проваленный тест. Запустите этот тест, и когда он достигнет вашей точки прерывания, сделайте w и посмотрите на стек. Если вы не понимаете, посмотрев в стек, как/где другой вызов сломался, то пройдите на полпути вверх по стеку, найдите некоторую часть кода, которая вам принадлежит, и поместите точку прерывания в этот файл, на одну строку выше той в трассировке стека. Попробуйте еще раз с новым тестом. Продолжайте двигаться вперед и назад, двигаясь вверх по стеку, чтобы выяснить, где ваш вызов сошел с рельс.

4. Поменяйте что-нибудь

Если вы все еще не можете разобраться, попробуйте сделать новый тест, в котором вы слегка изменили что-то. Можете ли вы заставить новый тест работать? Какая разница? Попробуйте изменить что-то еще. После того, как у вас появится тест и, возможно, дополнительные тесты тоже, можно смело начинать что-то менять в своем коде, чтобы посмотреть, сможете ли вы сузить радиус проблемы. Не забудьте начать устранение неполадок в новых условиях, чтобы вы могли легко отбросить изменения, которые не помогают.

5. Сделайте перерыв

На полном серьезе, когда все происходящее перестает быть забавным испытанием или игрой и начинает становиться действительно разочаровывающим процессом, ваш лучший план действий – абстрагироваться от проблемы. Сделать перерыв. Я настоятельно рекомендую пойти погулять и попытаться подумать о чем-то другом.

6. Записывайте все

Если по возвращению у вас вдруг не появится желание попробовать что-то еще, запишите любую имеющуюся у вас информацию о проблеме. Сюда должно входить:

  • Конкретный вызов, который вызывает проблему;
  • Что именно произошло, включая любые сообщения об ошибках или связанные сообщения журнала;
  • Именно то, что вы ожидали;
  • Что вы сделали до сих пор, чтобы найти проблему и любые подсказки, которые вы обнаружили при устранении неполадок.

Иногда информации будет слишком много, но, поверьте мне, это действительно может помочь. Постарайтесь быть кратким, но полным.

7. Попросите о помощи

Я часто замечаю, что простое записывание всей информации вызывает мысль о том, чего я еще не пробовал. Иногда, конечно, я понимаю, в чем проблема сразу после нажатия кнопки «Отправить». В любом случае, если вы все еще ничего не придумали после того, как все записали, попробуйте отправить кому-нибудь письмо. Сначала попробуйте коллег или других людей, вовлеченных в ваш проект, а затем переходите к спискам рассылки проекта. Не бойтесь просить о помощи. Большинство людей добры и полезны, и это особенно верно в сообществе Python.

Наверх
Меню