Вы из тех, кто для поиска багов использует функцию print()
, а не специализированные утилиты? Тогда вам не помешает побольше узнать о спектре возможностей, предоставляемых отладчиками. Они сэкономят ваше время и упростят отладку.
Отладка Python-кода с помощью print
Как уже говорилось ранее, кто-то используют print()
для отображения информации, которая помогает понять, что происходит в коде. Кто-то использует логи для тех же целей, но давайте не путать использование логов на продакшене и случаи, когда их используют во время поиска багов в коде и после удаляют.
Но самая большая проблема в использовании print()
— это необходимость вносить изменения в код и перезапускать приложение, чтобы увидеть изменения. Давайте разберёмся, почему отладчики эффективнее.
Команды отладчика Python
Главная задача отладчика — предоставить возможность заглянуть в процесс выполнения кода. Так, например, можно просмотреть стек вызовов, узнать значения переменных, установить брейкпоинты или запустить выполнение кода построчно. Можно провести аналогию с тем, как автомеханик заглядывает под капот автомобиля и начинает перебирать деталь за деталью, пока не найдет причину поломки.
Если вы работаете с Python, то можете не только просматривать код во время отладки, но даже запускать код из командной строки или изменять значения переменных на лету.
Python есть встроенный отладчик под названием pdb
. Это простая консольная утилита, которая обладает основной функциональностью для отладки кода. Но если вы ищете что-то более продвинутое, то стоит обратить внимание на ipdb
– отладчик с функциональностью из IPython.
Проще всего вызвать pdb
из кода, где вы работаете:
import pdb; pdb.set_trace()
Как только интерпретатор доберётся до этой строчки, запустится отладчик и в консоли будут доступны новые команды.
list (l)
Эта команда покажет часть кода, на выполнении которой сейчас находится интерпретатор. Можно передать два аргумента first
и last
для просмотра определённого участка кода. Если указать только first, то будет выведен код вокруг искомой строки.
up (p) и down (d)
Эти команды используются для передвижения по стеку вызовов. С их помощью можно отследить, откуда была вызвана текущая функция.
step (s) и next (n)
Другая пара не менее важных команд. С их помощью можно выполнять код построчно. Единственное различие между ними в том, что next(n)
перейдёт к следующей строке вне зависимости от вызываемых функций, а step(s)
перейдёт в вызванную функцию, если это возможно.
break (b)
Эта команда позволяет создавать брейкпоинты без внесений изменений в код. Ниже разберём этот этап более детально.
Краткий список команд pdb
:
args (a)
— выводит аргументы функции;continue (c)
или(cont)
— продолжит выполнение до первого брейкпоинта или до завершения программы;help (h)
— выводит список доступных команд или подсказки по определённой команде;jump (j)
— перепрыгивает к выполнению указанной строчки кода;list (i)
— выводит исходный код программы вокруг выбранной строки;expression (p)
— выводит значение выражения;pp
— выводит значение в «красивом» виде;quit
илиexit (q)
— отменяет выполнение программы;return (r)
— завершает выполнение текущей функции.
Продолжаем изучать отладчик Python
Рассмотренный ранее способ работы с отладчиком требовал внесения изменения в код для вывода чего-нибудь или установки брейкпоинта. Но часто при работе с внешними библиотеками появляется необходимость в их отладке. Конечно, можно открыть исходный код библиотеки и вызвать pdb
.
Но теперь есть возможность запускать приложение напрямую из отладчика без внесения изменения в код. Для этого воспользуемся следующей командой:
$ python3 -m pdb <имя скрипта>
Давайте разберём на примере. Есть простое приложение, которое отслеживает рабочее время. Для её работы используется библиотека requests
, отвечающая за выполнение HTTP-запросов. Попробуем прервать выполнение во время запроса. Как это сделать? Запустим приложение через отладчик и установим брейкпоинт внутри библиотеки requests
.
$ python3 -m pdb run.py
> /Users/.........................../run.py(1)<module>()
-> from TimeLog.app import run_app
(Pdb) b requests/sessions.py:555
Breakpoint 1 at /..................../lib/python3.6/site-packages/requests/sessions.py:555
(Pdb) c
Как можно заметить, не нужно указывать полный путь до библиотеки. Можно указать относительную ссылку от sys.path
. Таким же образом можно отлаживать и ваше приложение.
Теперь куда проще отлаживать код. Не надо вносить изменения в приложение или во внешние библиотеки.
Но что делать, если в приложении происходит много вызовов, а вам надо обработать только какой-то определённый? Можно точно указать условие, при выполнении которого отладчик будет прерывать выполнение приложения.
В данном примере прерывание произойдёт только в случае, если json
будет иметь в себе ключ time_entry
.
$ python3 -m pdb run.py
> /Users/...../run.py(1)<module>()
-> from TimeLog.app import run_app
(Pdb) b requests/sessions.py:555, json is not None and 'time_entry' in json
Breakpoint 1 at /Users/....../lib/python3.6/site-packages/requests/sessions.py:555
(Pdb) c
Отладка кода Django
Если вы используете Django, то скорее всего знаете, что, если в настройках значение параметра DEBUG
установлено как True
, то для каждого исключения будет выводиться отдельная страница с указанием типа исключения, стек вызовов, локальные переменные и т.д.
Если вы хотите прокачать отладчик, то установите django-extensions и используйте команду runserver_plus
для запуска сервера. Также можно указать пароль для доступа к отладке следующей командой:
WERKZEUG_DEBUG_PIN=1234 ./manage.py runserver_plus
Прим. перев. В WERKZEUG, начиная с версии 0.11, появилась возможность доступа по паролю к отладчику. Это сделано для повышения безопасности при попытках несанкционированного доступа.
Если вы используете django-extensions, то получите страницу со всеми вызовами, кодом и окном отладчика.
Процесс отладки осуществляется с помощью WSGI библиотеки Werkzeug.
Существует множество способов отладки приложений, но специализированные инструменты могут дать вам огромное преимущество по сравнению с другими разработчиками и помогут сэкономить время и силы при поиске багов.
Перевод статьи «Debugging Python Applications with pdb»