pdb - это интерактивный отладчик для Python, с помощью которого можно перемещаться по коду во время запуска вашей программы, смотреть и изменять значения переменных, построчно навигироваться по коду (в том числе углубляться во вложенности кода), назначать брейкпоинты и все прочие операции присущие отладчику.
Когда нет под рукой PuDB и не имеется возможности его установить, либо плывет графика в urwid я использую pdb.
Отладчик pdb внешне похож на gdb.
Либо в коде можно указать место откуда надо запускать отладчик:
import pdb; pdb.set_trace()
А post-mortem запускается так:
import pdb; pdb.pm()
Для тех кто не знает что такое post-mortem, то это режим в котором отладчик стартует сразу после необработанного исключения.
Также в коде можно вызывать скрипты через pdb.run/pdb.runcall, но приведенные выше типы запусков более популярные.
Список команд отладчика
h(elp) - отладчик выведет список допустимых команд. Выполните help <command> для того чтобы получить справку по конкретной команде;
q(uit), exit - выход из отладчика.
Общие команды
l(ist) [<first> [,<last>]] - печать исходного кода. Без передачи аргументов выводится +5 сверху и +5 снизу строк кода. Можно передать два аргумента "first" и "last" - номера строк диапазон которых надо выводить, если передать только один аргумент, то произойдет вывод +5 сверху и +5 снизу строк относительно указанного номера строки;
p <expression>, pp <expression> - "print" и "pprint" соответственно;
a(rgs) - выводит аргументы функции;
whatis <arg> - выведет тип объекта;
alias [<name> [<command> [<parameter>, <parameter> ...]]] - установить алиас на какую либо команду, например:
(Pdb) alias lv locals().keys()
(Pdb) alias gv pp globals().keys()
Алисы, помимо команд отладчика и инструкций интерпретатора могут вызывать другие алиасы. Выполнение без аргументов отображает список установленных алиасов, а если передать имя алиаса в качестве аргумента, то выведится его содержимое.
Для работы с аргументами алиаса нужно использовать следующий формат %<номер_аргумента>, а для обращения ко всем аргументам используйте %*, пример:
(Pdb) alias dirs !dir(%1)
dirs __name__
unalias <name> - удалить определенный алиас;
run [<args>...] - перезагружает скрипт с задаными параметрами, пример:
(Pdb) run runserver 8001
Restarting ./manage.py with arguments:
runserver 8001
> /home/adw0rd/work/project/manage.py(2)()
-> import os
(Pdb) c
Validating models...
0 errors found
Django version 1.4.1, using settings 'project.settings'
Development server is running at http://127.0.0.1:8001/
Quit the server with CONTROL-C.
Тем самым вы не выходите из сессии, и если у вас есть к примеру брейкпоинты, то вы их не потеряте. Также есть встроенный алиас restart, который запускает run без аргументов;
! - префикс для работы напрямую с интерпретатором, например вызов функций или обращение к переменным, всё что следует после префикса будет отправлено интерпретатору на выполнение, пример:
# Когда имя уникально можно делать и так:
test_var = 42
# Но когда оно совпадает с именем команды, надо так:
!step = 42
(Pdb) step = 42
> /home/adw0rd/work/project/manage.py(3)()
-> import sys
(Pdb) step
> /home/adw0rd/work/project/manage.py(5)()
-> if __name__ == "__main__":
(Pdb) !step = 42
(Pdb) !step
42
Навигация по коду
w(here) - выводит информаию о позиции в которой сейчас находитесь;
s(tep) - "step into", перейти во внутрь вызова объекта, если это возможно, иначе перейти к следующей строке кода;
n(ext) - "step over" (перешагнуть), перейти к следующей строке кода;
unt(il) - перейти к следующей строке кода, но гарантировано чтобы номер строки был больше чем текущий. Пример: если вы находитесь в конце тела цикла, но это не последняя итерация, то вас не отправит в начало тела цикла, а выполнится весь цикл и отладчик встанет на следующей строке после цикла, в отличии от next;
j(ump) <lineno> - перепрыгнуть на указанную строку кода не выполняя код находящийся между текущей позицией и указанной. Исключение составляют циклы for и код в блоке finally (т.к. должен быть обязательно выполнен). Также, вы можете перепрыгивать только внутри текущего фрейма (т.е. нижнего фрейма).
Точки останова
Далее просто "брейкопоинты", потому что мне привычнее их так называть.
При использовании листинга (команда "list") строки с брейкпоинтами помечаются префиксом "B":
(Pdb) b
Num Type Disp Enb Where
1 breakpoint keep yes at /home/adw0rd/work/project/manage.py:5
(Pdb) list
1 #!/usr/bin/env python
2 -> import os
3 import sys
4
5 B if __name__ == "__main__":
6 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
7 from django.core.management import execute_from_command_line
8 execute_from_command_line(sys.argv)
[EOF]
b(reak) ([<file>:]<lineno> | <function>) [<condition>] - установка и листинг брейкпоинтов. Аргументы позволяют указать файл и номер строки или функцию, где исполнение кода должно остановиться, пример:
(Pdb) b 5
Breakpoint 1 at /home/adw0rd/work/project/manage.py:5
(Pdb) b project/settings.py:10
Breakpoint 2 at /home/adw0rd/work/project/project/settings.py:10
(Pdb) b my_function
Breakpoint 3 at /home/adw0rd/work/project/manage.py:15
Для просмотра текущих установленных брейпоинтов, используйте команду break без аргументов:
(Pdb) b
Num Type Disp Enb Where
1 breakpoint keep yes at /home/adw0rd/work/project/manage.py:5
2 breakpoint keep yes at /home/adw0rd/work/project/project/settings.py:10
3 breakpoint keep yes at /home/adw0rd/work/project/manage.py:15
Отдельно стоит рассмотреть брейкпоинты с условием, брейкпоинт сработает если только условие будет верно, пример:
# Брейкпоинт выполнится только если переменная "some_var" будет больше 42
(Pdb) b my_function, some_var > 42
Breakpoint 4 at /home/adw0rd/work/project/manage.py:15
condition <bpnumber> <str_condition> - добавляет к существующему брейкпоинту условие, пример:
(Pdb) condition 3 True != False
tbreak - временный брекпоинт, после использования удаляется, имеет одинаковый синтаксис с break;
ignore <bpnumber> <count> - игнорировать count-раз определенный брейкпоинт. Если передать count равный нулю, то игнорирование сбросится;
c(ont(inue)) - продолжить (до первого брейкпоинта или до завершения работы программы);
disable <bpnumber> [<bpnumber> ...] и enable <bpnumber> [<bpnumber> ...] - первый деактивирует брейкпоинт, но НЕ удаляет его из списка брейкпоинтов. А второй снова активирует брейкпоинт, пример:
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../script.py:2
2 breakpoint keep yes at .../script.py:12
(Pdb) disable 1
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep no at .../script.py:2
2 breakpoint keep yes at .../script.py:12
(Pdb) enable 1
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../script.py:2
2 breakpoint keep yes at .../script.py:12
cl(ear) (<filename>:<lineno> | [<bpnumber>...]) - удаляет брейкпоинт(ы). Если передать номер брейкопинта то удалится только он, если ничего не пердавать - удалятся все брейкпоинты. Если передать путь и номер строки, то удалятся все брейкпоинты установленные в указанном месте;
commands [<bpnumber>] - написание дополнительных действий для брейкпоинта, например вывод локальных переменных и т.п. Пример:
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../script.py:2
(Pdb) commands 1
(com) p "DEBUG"
(com) pp locals()
(com) end
(Pdb) continue
# Тут идёт печать locals()
Для удаления необходимо снова запустить commands, но с пустым телом:
(Pdb) commands 1
(com) end
Сохранение настроек конфигурации
Для настроек pdb необходимо создать файл .pdbrc в корне домашней директории, либо в корне проекта. При этом совпадающие инструкции находящиеся в корне проекта переопределят тех кто находятся в корне домашней директории.
Пример файла ~/.pdbrc:
# Алиас, который позволяет указывать несколько объектов для dir()
# конечно он нужен только для примера...
alias dirs pp [dir(arg) for arg in "%*".split()]
Пример файла ~/work/project/.pdbrc:
# Пример переопределения алиаса:
alias dirs pp "OVERRIDDEN!"
Интеграция с Emacs
Во многих IDE есть поддержка pdb, не исключение и Emacs, достаточно запустить так:
M+x pdb
И вам предстанет консоль pdb в одной панели, а в другой реалтайм-листинг кода, почти PuDB, но всеравно менее удобнее.
Комментарии
лес зеленый и густой...непролазный и глухой. Ничего не понял :)
Мне всеравно кажется что python проще для понимания чем php :-)
Оставьте свой комментарий