Становимся опытным пользователем pdb

Что такое pdb?

pdb - модуль из стандартной библиотеки python, который позволяет:

  • пошагово выполнять инструкции из исходного кода
  • устанавливать условные точки останова (breakpoints)
  • исследовать стек вызовов (трассировка стеков, stack trace)
  • просматривать исходный код
  • исполнять python-код в контексте выполняемой программы
  • выполнять исследование аварийно завершившейся программы (постотладка)

В каких случаях использовать pdb?

Вовсе не обязательно постоянно обращаться к pdb, иногда достаточно обычных print-выражений или более-менее настроенного логгирования.

Но очень часто такие подходы оказываются не достаточно эффективными, так как не предоставляют контроля над выполняемой программой в ходе отладки. Плюс ко всему, после выполнения необходимых проверок нам нужно пройтись по коду и удалить все добавленные print-выражения. Такой сложности не возникает в случае, если мы использовали logging, но оба варианта раздувают исходный код и совсем не расширяют возможностей процесса отладки.

Как запустить pdb

Есть несколько вариантов запуска отладчика pdb, на выбор в зависимости от ситуации.

Запуск программы через отладчик

Мы можем запустить сам скрипт через отладчик, используя аргумент -m pdb. Пример для script.py:

$ python -m pdb script.py
 > /pdb-mupy/script.py(1)()
 -> """I am the first script in this demo"""
 (Pdb)

В этом режиме Python остановит выполнение программы на первой строке и вы окажетесь в окружении отладчика ((Pdb) - приглашение командной строки pdb). Теперь можно либо выставить контрольные точки, либо продолжить выполнение программы.

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

Запуск в отладчике определенного кода

Вместо того, чтобы запускать в отладчике всю программу, используя pdb.run, pdb.runeval и pdb.runcall мы можем запустить определенные строки (методы, функции) из исходного кода.

>>> import pdb
>>> import script
>>> pdb.run('script.divide(10, 5)')
> (1)()->None
(Pdb) s   # we can run any pdb command here
--Call--
> /pdb-mupy/script.py(6)divide()
-> def divide(numerator, denominator):
(Pdb) n
> /pdb-mupy/script.py(7)divide()
-> return numerator / denominator
(Pdb) p numerator, denominator
(10, 5) (Pdb) c
>>>

В данном случае <string>(1)<module>() означает, что мы в самом начале строки, переданной run(), и еще не было выполнено никаких инструкций. В примере выше мы запустили выполнение функции divide при помощи команды s (не переживайте о s, n, c - мы детально рассмотрим эти команды позднее).

runeval() выполняет те же действия, что и run(), но при этом возвращает результат выполнения.

runcall() позволяет передавать вызываемый python-объект, вместо строки.

>>> pdb.runcall(script.divide, 10, 5)
> /pdb-mupy/script.py(7)divide()
-> return numerator / denominator
(Pdb)

Установка контрольной точки

Это наиболее часто используемый метод отладки программ, он представляет собой просто добавление строки pdb.set_trace() в исходный код программы в том месте, где необходимо остановить выполнение и запустить отладчик.

Постотладка

Режим постотладки позволяет изучить состояние программы на момент аварийного завершения, используя информацию об ошибке, traceback. Сама программа на момент запуска постотладчика уже находится в завершенном состоянии, то есть мы не можем следить за её выполнением или просматривать исходный код. Но нам доступно состояние программы на момент возникновения ошибки, что тоже может помочь.

Как мы уже обговаривали, программа, запущенная при помощи -m pdb, автоматически переходит в режим постотладки при возникновении исключения. Другой вариант - вызвать pdb.pm() или pdm.post_mortem().

pdb.pm() запустит режим постотладки, основываясь на данных исключения в sys.last_traceback.

pdb.post_mortem() принимает необязательный аргумент, в котором можно передать traceback-объект. Иначе, как и pdb.pm(), постотладка будет запущена с использованием информации об исключении из sys.last_traceback.

>>> import pdb
>>> import script
>>> script.divide(10, 0)
Traceback (most recent call last):
  File "", line 1, in 
    script.divide(10, 0)
  File "script.py", line 7, in divide
    return numerator / denominator
ZeroDivisionError: integer division or modulo by zero

Теперь мы можем анализировать состояние программы на момент исключения, используя pdb.pm().

>>> pdb.pm()
> /Users/ashwini/work/instamojo/pdb-mupy/script.py(7)divide()
-> return numerator / denominator
(Pdb) args  # Arguments passed to the function at that time
numerator = 10
denominator = 0

Аналогичного эффекта можно добиться с pdb.post_mortem(), передав ему объект исключения:

>>> import sys
>>> pdb.post_mortem(sys.last_traceback)
> /Users/ashwini/work/instamojo/pdb-mupy/script.py(7)divide()
-> return numerator / denominator
(Pdb)

Либо запустив без аргументов в момент возникновения исключения:

>>> try:
...     script.divide(10, 0)
... except Exception:
...     pdb.post_mortem()
...
> /Users/ashwini/work/instamojo/pdb-mupy/script.py(7)divide()
-> return numerator / denominator
(Pdb)

Основные команды pdb

Как мы уже видели, pdb имеет свою командную оболочку (Pdb), которая поддерживает определенный набор команд, значительно облегчая процесс отладки. В этой части статьи мы рассмотрим основные команды.

Перед тем, как начать разбираться с основным материалом, необходимо усвоить используемую систему обозначений. Например, команда написанная как c(ont(inue)) означает, что мы в режиме командной строки pdb мы можем использовать c, cont или continue. Квадратные скобочки ([]) после самой команды представляют собой набор необязательных аргументов, которые данная команда принимает. Аргумент, указанный без квадратных скобок является обязательным.

h(elp) [command]

help или просто h выводит страницу с документацией для определенной pdb команды. Если при вызове help не было указано никакой команды (список аргументов пуст), то будет отображен список всех доступных в оболочке команд:

EOF bt cont enable jump pp run unt a c continue exit l q s until alias cl d h list quit step up args clear debug help n r tbreak w b commands disable ignore next restart u whatis break condition down j p return unalias where

Получить информацию по использованию команды args:

(Pdb) help args
a(rgs)
Print the arguments of the current function.

Команда help может сэкономить вам время избавив от поиска в официальной python документации, в случае, если вы забыли ту или иную команду.

p или pp

Для того, чтобы вывести на экран значение переменной внутри отладчика, используется p для обычного форматирования и pp для "красивого" - с отступами и новыми строками. Стандартный print так же можно использовать, но эта команда не относится к pdb.

a(rgs)

args выводит на экран список аргументов и их значений в текущей функции.

>>> pdb.runcall(script.divide, 10 , 15)
> /pdb-mupy/script.py(7)divide()
-> return numerator / denominator
(Pdb) args
numerator = 10
denominator = 15

q(uit)

Для выхода из отладчика используется q или quit.

!(выражение)

Для того, чтобы выполнить python-код в отладчике, мы можем использовать команду !, указав python-код после неё. Без ! выполнение кода вызовет ошибку, если его содержимое пересекается хотя бы с одной встроенной pdb-командой, поэтому рекомендуется всегда использовать ! для запуска python-кода.

$ python -m pdb script.py
> /pdb-mupy/script.py(1)()
-> """I am the first script in this demo"""
(Pdb) !c = 2  # Define a variable named c
(Pdb) p c
2

Без ! этот пример кода будет вести себя некорректно, так как pdb посчитает, что мы пробуем выполнить команду c

(Pdb) c = 2
2
The program finished and will be restarted:
> /pdb-mupy/script.py(1)()
-> """I am the first script in this demo"""
(Pdb)

run [args...]

run позволяет перезапускать программу. Это удобно, если мы хотим перезапустить программу с другими аргументами, не покидая окна отладчика.

$ python -m pdb script.py 10 5
> /pdb-mupy/script.py(1)()
-> """I am the first script in this demo"""
(Pdb) !import sys
(Pdb) p sys.argv
['script.py', '10', '5']

Давайте запустим программу с другими аргументами

(Pdb) run 30 40
Restarting script.py with arguments:
    30 40
> /pdb-mupy/script.py(1)()
-> """I am the first script in this demo"""
(Pdb) !import sys
(Pdb) p sys.argv
['script.py', '30', '40']

l(ist) [first[, last]]

Команда l или list используется для просмотра исходного кода

Без аргументов она выводит на экран 11 строк исходного кода программы с текущей строкой посередине. Если было передано 2 аргумента, то выводится исходный код в указанном диапазоне строк.

$ python -m pdb script.py
> /pdb-mupy/script.py(1)()
-> """I am the first script in this demo"""

Просмотрим 11 строк относительно текущей:

(Pdb) list
  1  -> """I am the first script in this demo"""
  2
  3     import sys
  4
  5
  6     def divide(numerator, denominator):
  7         return numerator / denominator
  8
  9
 10     if __name__ == '__main__':
 11         numerator = int(sys.argv[1])

Просмотрим строки с 5 по 8:

(Pdb) list 5, 8
  5
  6     def divide(numerator, denominator):
  7         return numerator / denominator
  8

alias [name [command]] или unalias

alias используется, чтобы добавлять короткие имена (alias) командам в отладчике. Соответственно, unalias удаляет добавленный ранее alias-ы.

Предположим, мы хотим сделать короткое имя для команды, которая возвращает список квадратов значений в указанном диапазоне:

(Pdb) alias squares [i**2 for i in xrange(%1)]
(Pdb) squares 5
[0, 1, 4, 9, 16]

В данном примере %1 - аргумент, ожидаемый нашим alias-ом (непосредственно в коде - 5). Если нам нужно передать больше - можем использовать %2, %3 и так далее.

Короткие имена можно создавать на основе других:

(Pdb) alias squares_7 squares 7

Теперь выполнение squares_7 эквивалентно выполнению squares 7

(Pdb) squares_7
[0, 1, 4, 9, 16, 25, 36]

Чтобы удалить alias используется команда unalias с указанием названия короткой команды в качестве аргумента.

Пошаговое выполнение кода

Одна из самых удобных возможностей pdb - различные варианты выполнения кода:

  • последовательно строка за строкой
  • последовательно с заходом внутрь функций
  • пропуская цикл
  • пропуская функции

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

n(ext)

Команда n или next выполняет код, содержащийся в текущей строке и переходит к следующей строке текущей функции.

s(tep)

Команда s или step очень похожа на next, однако её действие отличается, если в текущей строке не просто выражение, а вызов функции. В этом случае pdb войдет внутрь функции (или другого вызываемого объекта) и продолжит построчное выполнение кода уже внутри. В случае next, pdb перешел бы к выполнению инструкций в следующей строке текущей функции.

unt(il)

При помощи команды until можно указать pdb выполнять исходный код до тех пор, пока не будет достигнута строка с номером большим, чем текущая. Удобно, если нужно быстро выйти из цикла.

r(eturn)

r (или return) переносит выполнение к концу текущей функции. В случае с модулем (когда выполняются инструкции в корне файла, а не внутри функций), выполнение переносится на последнюю строку в файле. Команда удобна в случае, когда необходимо быстро пропустить весь код текущей функции.

c(ont(inue))

c или cont или continue позволяет нам выполнять код без задрежек и остановок после того, как мы закончили процесс отладки. Если где-то дальше в коде имеются точки останова, то выполнение снова будет остановлено по достижении соответствующей строки.

Давайте поэксперименитурем: проведем отладку скрипта next_and_step_until.py используя изученные команды. Мы установили запуск отладки на строке 19 при помощи pdb.set_trace(), таким образом отладчик будет запущен на следующей корректной строке с python-кодом скрипта, т.е. на строке 21.

$ python next_and_step_until.py
> /Users/ashwini/work/instamojo/pdb-mupy/next_and_step_until.py(21)()
-> knights()  # Чтобы просто выполнить функцию используем n(ext).
(Pdb)

Теперь, чтобы выполнить функцию knights() не заходя в неё, "на полной скорости", используем команду n(ext). В консоли будут напечатаны результаты выполнения print-выражений из этой функции а pdb остановится на следующей строке кода:

(Pdb) n
We are the Knights who say ni!
Get us a shrubbery.
> /Users/ashwini/work/instamojo/pdb-mupy/next_and_step_until.py(22)()
-> credits()  # Чтобы выполнить функцию построчно, используем s(tep).
(Pdb)

Потом, предположим, мы решили отладить логику функции credits() и использовали для этого команду s(tep):

(Pdb) s
--Call--
> /pdb-mupy/next_and_step_until.py(11)credits()
-> def credits():
(Pdb) n
> /pdb-mupy/next_and_step_until.py(12)credits()
-> print "A Møøse once bit my sister... No realli!"
(Pdb) n
A Møøse once bit my sister... No realli!
> /pdb-mupy/next_and_step_until.py(13)credits()
-> print "We apologise for the fault in the print statements."
(Pdb)

Завершив работу с этой функцией мы можем воспользоваться командой r(eturn) для перемещения к последней строке кода в этой функции и n(ext) чтобы выйти из неё:

(Pdb) r
We apologise for the fault in the print statements.
Those responsible have been sacked.
--Return--
> /Users/ashwini/work/instamojo/pdb-mupy/next_and_step_until.py(15)credits()->'M\xc3\xb8\xc...pretti nasti.'
-> return "Møøse bites Kan be pretti nasti."
(Pdb) n
> /Users/ashwini/work/instamojo/pdb-mupy/next_and_step_until.py(24)()
-> for i in range(1, 5):

Теперь мы находимся внутри цикла, и ни n(ext), ни s(tep) не помогут выполнить его в один шаг. Для того, чтобы пропустить цикл, мы при помощи n(ext) перемещаемся к его последней строке и используем unt(il):

-> for i in range(1, 5):
(Pdb) n
> /pdb-mupy/next_and_step_until.py(26)()
-> print "Shrubbery #{}".format(i)
(Pdb) until
Shrubbery #1
Shrubbery #2
Shrubbery #3
Shrubbery #4
> /pdb-mupy/next_and_step_until.py(28)()
-> print "We have found the Holy Grail."
(Pdb)

Теперь мы можем продолжить выполнение программы до самого конца при помощи команды c(ont(inue)):

(Pdb) cont
We have found the Holy Grail.

Перемещение по стеку

До текущего момента мы перемещались по коду только вперед: строка за строкой с возможностью заходить внутрь вызываемых функций. Но pdb предоставляет возможность перемещаться по стеку выполняемых функций как вперед, так и назад.

Лучший способ продемонстировать эту возможность

Лучшим примером, демонстрирующим эту возможность, является перемещение по рекурсивно исполняемой функции. Исходный код находится в файле recursive.py.

В этом разделе мы будем использовать три команды: u(p), d(own) и w(here).

w(here)

w или where выводит в консоль полный путь вплоть до самого последнего фрейма стека и отмечает текущий фрейм при помощи стрелочки.

Давайте попробуем: запустим скрипт, а когда он остановится на месте установленной контрольной точки, выполним where, чтобы посмотреть полный стек вызовов:

$ python recursive.py
> /pdb-mupy/recursive.py(10)func()
-> return 0
(Pdb) where
  /pdb-mupy/recursive.py(14)()
-> print (func(4))
  /pdb-mupy/recursive.py(7)func()
-> return func(n - 1)
  /pdb-mupy/recursive.py(7)func()
-> return func(n - 1)
  /pdb-mupy/recursive.py(7)func()
-> return func(n - 1)
  /pdb-mupy/recursive.py(7)func()
-> return func(n - 1)
> /pdb-mupy/recursive.py(10)func()  # Current frame
-> return 0
(Pdb)

В этом выводе отдельный символ > указывает на текущий фрейм.

Теперь мы можем перемещаться по стеку используя u(p) и d(own). Давайте переместимся вверх на два шага и посмотрим значения аргументов, использовав a(rgs). Контрольная точка была установлена на строке в которой параметр n равнялся нулю. Теперь, мы вернулись на два шага назад, и n = 2:

(Pdb) u
> /pdb-mupy/recursive.py(7)func()
-> return func(n - 1)
(Pdb) u
> /pdb-mupy/recursive.py(7)func()
-> return func(n - 1)
(Pdb) args
n = 2
(Pdb)

Аналогичным образом мы можем переместиться вниз (вперед):

(Pdb) d
> /pdb-mupy/recursive.py(7)func()
-> return func(n - 1)
(Pdb) args
n = 1

u(p) так же оказывается полезным в случае, если вы случайно вошли внутрь функции при помощи s(tep) и хотите вернуться обратно.

Контрольные точки (Breakpoints)

Пока что мы видели только один сопособ установить контрольную точку: изменяя исходный код, добавляя вызов pdb.set_trace() в месте, где необходимо начать отладку. Но pdb предоставляет возможность динамически установить точку останова в зависимости от определенных условий не изменяя код исполняемой программы. В этом разделе мы будем использовать скрипт breakpoints.py.

b(reak) [[filename:]lineno | function[, condition]]

Мы можем установить контрольную точку в текущем файле указав номер строки или имя функции. Чтобы установить контрольную точку в другом файле, необходимо сначала указать его имя (файл должен находиться в python-пути).

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

Необязательный параметр condition в синтаксисе команды должен быть валидным python-выражением. В случае, если результат выполнения этого выражения - True, то по достижении соответсвующей контрольной точки выполнение программы будет остановлено для отладки. Вычисление condition выполняется в том же окрежении, в котором была установлена контрольная точка.

Несколько примеров установки контрольных точек:

  • break 13 - устанавливает контрольную точку на 13 строке
  • break divide - устанавливает контрольную точку на функции divide
  • break divide, denominator == 0 - устанавливает контрольную точку на функции divide только в том случае, если denominator равен нулю
$ python -m pdb breakpoints.py 10 0
> /pdb-mupy/breakpoints.py(2)()
-> import sys
(Pdb) break divide, denominator == 0
Breakpoint 1 at /pdb-mupy/breakpoints.py:5

Получить список установленных контрольных точек можно при помощи команды b(reak). Num - порядковый номер точки, Disp == keep означает, что точка постоянная, а End = yes указывает, что эта точка включена в текущий момент.

(Pdb) break
    Num Type         Disp Enb   Where
    1   breakpoint   keep yes   at /pdb-mupy/breakpoints.py:5
        stop only if denominator == 0
    (Pdb) c

С учетом значения denominator на момент запуска скрипта, точка останова сработала:

> /pdb-mupy/breakpoints.py(8)divide()
    -> print "Calculating {}/{}".format(numerator, denominator)
    (Pdb) args
    numerator = 10.0
    denominator = 0.0

Давайте попробуем запустить программу с другими аргументами:

(Pdb) run 10 5
Restarting breakpoints.py with arguments:
    10 5
> /pdb-mupy/breakpoints.py(2)()
-> import sys
(Pdb) c
Calculating 10.0/5.0
2.0
The program finished and will be restarted
> /pdb-mupy/breakpoints.py(2)()
-> import sys

Так как denominator в этот раз имел значение, отличное от нуля, остановки в контрольной точке не произошло.

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at /pdb-mupy/breakpoints.py:5
    stop only if denominator == 0
    breakpoint already hit 2 times

Контрольные точки остаются даже после перезапуска программы в -m pdb режиме.

tbreak [[filename:]lineno | function[, condition]]

tbreak устанавливает временную контрольную точку. Она пропадает после того первого выполнения. Удобно, если необходимо установить точку останова в цикле только для первого вызова функции.

$ python -m pdb breakpoints.py 10 5
> /pdb-mupy/breakpoints.py(2)()
-> import sys
(Pdb) tbreak divide, denominator == 0
Breakpoint 1 at/pdb-mupy/breakpoints.py:5
(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   del  yes   at /pdb-mupy/breakpoints.py:5
    stop only if denominator == 0

Обратите внимание на значение Disp в этот раз. del вместо keep означает, что контрольная точка - временная.

(Pdb) c
Calculating 10.0/5.0
2.0
The program finished and will be restarted
> /Users/ashwini/work/instamojo/pdb-mupy/breakpoints.py(2)()
-> import sys

Программа завершила свое выполнение и была автоматически перезапущена, поскольку условия condition не были выполнены. Давайте исправим это и перезапустим выполнение:

(Pdb) run 10 0
Restarting breakpoints.py with arguments:
    10 0
> /pdb-mupy/breakpoints.py(2)()
-> import sys
(Pdb) c
Deleted breakpoint 1
> /Users/ashwini/work/instamojo/pdb-mupy/breakpoints.py(8)divide()
-> print "Calculating {}/{}".format(numerator, denominator)
(Pdb) break
(Pdb)

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

cl(ear) [filename:lineno | bpnumber [bpnumber ...]]

Удалить контрольную точку можно при помощи команды cl(ear).

disable [bpnumber [bpnumber ...]] или enable [bpnumber [bpnumber ...]]

Временно отключить контрольную точку можно при помощи команды disable. Для повторной активации используется команда enable.

ignore bpnumber [count]

Пропустить определенную контрольную точку можно при помощи команды ignore. При помощи параметра count можно указать сколько раз её нужно пропускать. В этом случае контрольная точка снова становится активной, как только count принимает значение 0.

condition bpnumber [condition]

Чтобы обновить или добавить условие к контрольной точке, можно использовать команду condition.

Если условия будут представлять собой некорректный python-код, результатом будет True. Но, в то же время, таком случае временная контрольная точка не будет удалена, а счетчик ignore - уменьшен. Такое поведение выбрано, чтобы уведомить пользователя о нештатной ситуации.

commands [bpnumber]:

Еще одна очень полезная команда, относящаяся к контрольным точкам - commands. Вызванная определенным образом, она может выполнять функции print в нашем коде.

Эта команда позволяет автоматически выполнять различные команды, по достижении контрольной точки. Давайте добавим точку останова в функцию divide и выведем в консоль немного информации, используя commands.

$ python -m pdb breakpoints.py 10 5
> /pdb-mupy/breakpoints.py(2)()
-> import sys
(Pdb) break divide
Breakpoint 1 at /Users/ashwini/work/instamojo/pdb-mupy/breakpoints.py:5

В режиме commands приглашение в консоли выглядит как com. Чтобы выйти из этого режима, используется end.

(Pdb) commands 1
(com) args
(com) p "Inside divide()"
(com) end
(Pdb) c
numerator = 10.0
denominator = 5.0
'Inside divide()'
> /pdb-mupy/breakpoints.py(8)divide()
-> print "Calculating {}/{}".format(numerator, denominator)

Как мы видим, как только выполнение программы достигло установленной контрольной точки, в консоль была выведена дополнительная информация.

Аналогично мы можем использовать команды cont, next и т.д. Но эти команды будут так же выполнять функцию end, отправляя нас к следующей контрольной точке, которая может иметь свой собственный набор команд, тем самым, вызывая неопределенное поведение pdb.

Еще одна из команд, доступных внутри com-режима - silent. Если эта команда присутствует в списке добавленных команд, то по достижении контрольной точки вспомогательная информация в консоль выводиться не будет.

$ python -m pdb breakpoints.py 10 5
> /pdb-mupy/breakpoints.py(2)()
-> import sys
(Pdb) break divide
Breakpoint 1 at /pdb-mupy/breakpoints.py:5
(Pdb) commands 1
(com) args
(com) p "Inside divide()"
(com) silent
(com) cont
(Pdb) c
numerator = 10.0
denominator = 5.0
'Inside divide()'
Calculating 10.0/5.0
2.0
The program finished and will be restarted
> /pdb-mupy/breakpoints.py(2)()
-> import sys
(Pdb)

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

> /pdb-mupy/breakpoints.py(8)divide()
-> print "Calculating {}/{}".format(numerator, denominator)

Хитрости и рекомендации

  1. Используйте .pdbrc-файл. Команды из этого файла выполняются в начале отладочной сессии. Файл может находиться в корне домашней директории, или в текущей папке.
  2. Нажатие на клавишу enter позволяет выполнить последнюю команду повторно. Исключение - list.
  3. Чтобы ввести несколько команда в одной строке используйте ;; в качестве разделителя.

Нововведения в python3

Python3.3+

  • Доступно автодополнение команд и аргументов по нажатию на tab, используется readline модуль.

Python3.2+

  • pdb.py принимает -c параметр, позволяющй устанавливать команды аналогично .pdbrc
  • Новая команда ll позволяет просмотреть исходный текущей функции или фрейма
  • Новая команда source позволяет просмотреть исходный код около выражения: source expression
  • Новая команда interact позволяет начать интерактивную shell-сессию в отладчике используя globals() и locals() в текущем фрейме. В python2 это можно сделать следующим образом:
!import code
code.interact(local=vars())

Оригинал статьи на английском: Become a pdb power-user