pdb — Отладчик Python

Источник: Lib/pdb.py


Модуль pdb определяет интерактивный отладчик исходного кода для программ на Python. Он поддерживает установку (условных) точек останова и одиночных шагов на уровне исходной строки, просмотр стековых кадров, листинг исходного кода и оценку произвольного кода Python в контексте любого стекового кадра. Он также поддерживает посмертную отладку и может быть вызван под управлением программы.

Отладчик является расширяемым - фактически он определен как класс Pdb. В настоящее время это не документировано, но это легко понять, прочитав исходный текст. Интерфейс расширения использует модули bdb и cmd.

См.также

Модуль faulthandler

Используется для явного сброса трассировки Python, при ошибке, после таймаута или по сигналу пользователя.

Модуль traceback

Стандартный интерфейс для извлечения, форматирования и печати трасс стека программ на Python.

Типичным способом проникновения в отладчик является вставка:

import pdb; pdb.set_trace()

Или:

breakpoint()

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

Изменено в версии 3.7: Вместо import pdb; pdb.set_trace() можно использовать встроенную функцию breakpoint(), если она вызывается с параметрами по умолчанию.

def double(x):
   breakpoint()
   return x * 2
val = 3
print(f"{val} * 2 is {double(val)}")

Подсказка отладчика - (Pdb), это индикатор того, что вы находитесь в режиме отладки:

> ...(2)double()
-> breakpoint()
(Pdb) p x
3
(Pdb) continue
3 * 2 is 6

Изменено в версии 3.3: Для команд и аргументов команд доступно заполнение табуляции с помощью модуля readline, например, в качестве аргументов команды p предлагаются текущие глобальные и локальные имена.

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

python -m pdb myscript.py

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

Изменено в версии 3.2: Добавлена опция -c для выполнения команд, как если бы они были заданы в файле .pdbrc; см. Команды отладчика.

Изменено в версии 3.7: Добавлена опция -m для выполнения модулей аналогично тому, как это делает python -m. Как и в случае со скриптом, отладчик приостановит выполнение непосредственно перед первой строкой модуля.

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

>>> import pdb
>>> def f(x):
...     print(1 / x)
>>> pdb.run("f(2)")
> <string>(1)<module>()
(Pdb) continue
0.5
>>>

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

>>> import pdb
>>> def f(x):
...     print(1 / x)
...
>>> f(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
ZeroDivisionError: division by zero
>>> pdb.pm()
> <stdin>(2)f()
(Pdb) p x
0
(Pdb)

Изменено в версии 3.13: Реализация PEP 667 означает, что присваивания имен, сделанные через pdb, будут немедленно влиять на активную область видимости, даже если они выполняются внутри optimized scope.

В модуле определены следующие функции; каждая из них входит в отладчик немного по-разному:

pdb.run(statement, globals=None, locals=None)

Выполнить выражение (заданное в виде строки или объекта кода) под контролем отладчика. Перед выполнением кода появляется приглашение отладчика; вы можете установить точки останова и набрать continue, либо выполнить переход по утверждению с помощью step или next (все эти команды описаны ниже). Необязательные аргументы globals и locals задают окружение, в котором будет выполняться код; по умолчанию используется словарь модуля __main__. (См. пояснения к встроенным функциям exec() или eval()).

pdb.runeval(expression, globals=None, locals=None)

Оценить выражение (заданное в виде строки или объекта кода) под контролем отладчика. При возврате runeval() возвращает значение выражения. В остальном эта функция аналогична run().

pdb.runcall(function, *args, **kwds)

Вызов функции (объекта функции или метода, а не строки) с заданными аргументами. Когда runcall() возвращается, возвращается то, что вернул вызов функции. При вводе функции появляется приглашение отладчика.

pdb.set_trace(*, header=None)

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

Изменено в версии 3.7: Аргумент header, содержащий только ключевое слово.

Изменено в версии 3.13: set_trace() войдет в отладчик сразу, а не на следующей выполняемой строке кода.

pdb.post_mortem(traceback=None)

Вводит посмертную отладку заданного объекта traceback. Если traceback не задан, то используется тот, который относится к обрабатываемому в данный момент исключению (если используется значение по умолчанию, то исключение должно обрабатываться).

pdb.pm()

Введите посмертную отладку исключения, найденного в sys.last_exc.

Функции run* и set_trace() - это псевдонимы для инстанцирования класса Pdb и вызова одноименного метода. Если вы хотите получить доступ к дальнейшим функциям, вам придется сделать это самостоятельно:

class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True)

Pdb - класс отладчика.

Аргументы completekey, stdin и stdout передаются в базовый класс cmd.Cmd; см. описание в нем.

Аргумент skip, если он задан, должен представлять собой итерацию шаблонов имен модулей в стиле glob. Отладчик не будет входить во фреймы, возникающие в модуле, который соответствует одному из этих шаблонов. [1]

По умолчанию Pdb устанавливает обработчик сигнала SIGINT (который посылается, когда пользователь нажимает кнопку Ctrl-C на консоли), когда вы подаете команду continue. Это позволит вам снова войти в отладчик, нажав Ctrl-C. Если вы хотите, чтобы Pdb не трогал обработчик SIGINT, установите nosigint в true.

Аргумент readrc по умолчанию равен true и определяет, будет ли Pdb загружать файлы .pdbrc из файловой системы.

Пример вызова для включения трассировки с помощью skip:

import pdb; pdb.Pdb(skip=['django.*']).set_trace()

Поднимает auditing event pdb.Pdb без аргументов.

Изменено в версии 3.1: Добавлен параметр skip.

Изменено в версии 3.2: Добавлен параметр nosigint. Ранее обработчик SIGINT никогда не устанавливался Pdb.

Изменено в версии 3.6: Аргумент readrc.

run(statement, globals=None, locals=None)
runeval(expression, globals=None, locals=None)
runcall(function, *args, **kwds)
set_trace()

См. документацию по функциям, описанным выше.

Команды отладчика

Команды, распознаваемые отладчиком, перечислены ниже. Большинство команд можно сократить до одной или двух букв, как указано; например, h(elp) означает, что для ввода команды help можно использовать либо h, либо help (но не he или hel, ни H, ни Help или HELP). Аргументы команд должны быть разделены пробелами (пробелами или табуляциями). Необязательные аргументы заключаются в квадратные скобки ([]) в синтаксисе команды; квадратные скобки не должны быть набраны. Альтернативы в синтаксисе команды разделяются вертикальной полосой (|).

При вводе пустой строки повторяется последняя введенная команда. Исключение: если последней командой была команда list, то будут перечислены следующие 11 строк.

Команды, которые отладчик не распознает, принимаются за операторы Python и выполняются в контексте отлаживаемой программы. Утверждения Python также могут иметь префикс в виде восклицательного знака (!). Это мощный способ проверить отлаживаемую программу; можно даже изменить переменную или вызвать функцию. Если в таком операторе возникает исключение, то выводится имя исключения, но состояние отладчика не изменяется.

Изменено в версии 3.13: Выражения/заявления, префиксом которых является команда pdb, теперь правильно определяются и выполняются.

Отладчик поддерживает aliases. Псевдонимы могут иметь параметры, что позволяет в определенной степени адаптироваться к рассматриваемому контексту.

Несколько команд могут быть введены в одной строке, разделенные ;;. (Одиночный ; не используется, так как он является разделителем для нескольких команд в строке, которая передается парсеру Python). Разделение команд не требует особого подхода; ввод разделяется по первой паре ;;, даже если она находится в середине строки с кавычками. Обходным решением для строк с двойной точкой с запятой является использование неявной конкатенации строк ';'';' или ";"";".

Чтобы задать временную глобальную переменную, используйте удобную переменную. Переменная удобства - это переменная, имя которой начинается с $. Например, $foo = 1 устанавливает глобальную переменную $foo, которую можно использовать в сеансе отладчика. Переменные удобства очищаются при возобновлении выполнения программы, поэтому вероятность того, что они будут мешать работе программы, меньше, чем при использовании обычных переменных, таких как foo = 1.

Есть три предустановленные переменные удобства:

  • $_frame: текущий кадр, который вы отлаживаете

  • $_retval: возвращаемое значение, если кадр возвращается

  • $_exception: исключение, если фрейм поднимает исключение

Added in version 3.12: Добавлена функция переменная удобства.

Если файл .pdbrc существует в домашнем каталоге пользователя или в текущем каталоге, он читается в кодировке 'utf-8' и выполняется так, как если бы он был набран в приглашении отладчика, за исключением того, что пустые строки и строки, начинающиеся с #, игнорируются. Это особенно полезно для псевдонимов. Если существуют оба файла, то первым считывается тот, который находится в домашнем каталоге, и определенные в нем псевдонимы могут быть отменены локальным файлом.

Изменено в версии 3.2: .pdbrc теперь может содержать команды, продолжающие отладку, например continue или next. Ранее эти команды не имели никакого эффекта.

Изменено в версии 3.11: .pdbrc теперь читается с кодировкой 'utf-8'. Ранее он читался с кодировкой системной локали.

h(elp) [command]

Без аргумента выводит список доступных команд. При указании команды в качестве аргумента выводит справку по этой команде. help pdb выводит полную документацию (docstring модуля pdb). Поскольку аргумент command должен быть идентификатором, для получения справки по команде ! необходимо ввести help exec.

w(here)

Печать трассировки стека с последним кадром внизу. Стрелка (>) указывает на текущий кадр, который определяет контекст большинства команд.

d(own) [count]

Переместите текущий кадр на количество (по умолчанию один) уровней вниз в трассировке стека (на более новый кадр).

u(p) [count]

Переместить текущий кадр на количество (по умолчанию один) уровней вверх в трассировке стека (на более старый кадр).

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

С аргументом lineno устанавливает прерывание на строке lineno в текущем файле. Номер строки может быть дополнен filename и двоеточием, чтобы указать точку останова в другом файле (возможно, еще не загруженном). Поиск в файле выполняется по sys.path. Допустимыми формами filename являются /abspath/to/file.py, relpath/file.py, module и package.module.

С аргументом function установите прерывание на первом исполняемом операторе внутри этой функции. function может быть любым выражением, которое оценивается как функция в текущем пространстве имен.

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

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

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

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

Временная точка останова, которая автоматически удаляется при первом нажатии. Аргументы те же, что и для break.

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

С аргументом filename:lineno очистите все точки останова на этой строке. Список номеров точек останова, разделенных пробелами, очищает эти точки останова. Без аргумента - очистить все точки останова (но сначала запросить подтверждение).

disable bpnumber [bpnumber ...]

Отключить точки останова, заданные в виде списка номеров точек останова, разделенных пробелами. Отключение точки останова означает, что она не может привести к остановке выполнения программы, но, в отличие от очистки точки останова, она остается в списке точек останова и может быть (повторно) включена.

enable bpnumber [bpnumber ...]

Включите указанные точки останова.

ignore bpnumber [count]

Устанавливает счетчик игнорирования для заданного номера точки останова. Если значение count опущено, счетчик игнорирования устанавливается в 0. Точка останова становится активной, когда счетчик игнорирования равен нулю. Если значение count ненулевое, оно уменьшается каждый раз, когда достигается точка останова, и точка останова не отключена, а любое связанное с ней условие оценивается как true.

condition bpnumber [condition]

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

commands [bpnumber]

Укажите список команд для точки останова с номером bpnumber. Сами команды появляются в следующих строках. Введите строку, содержащую только end, чтобы завершить команды. Пример:

(Pdb) commands 1
(com) p some_variable
(com) end
(Pdb)

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

Если аргумент bpnumber отсутствует, commands ссылается на последнюю установленную точку останова.

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

Указание любой команды, возобновляющей выполнение (в настоящее время это continue, step, next, return, jump, quit и их аббревиатуры), завершает список команд (как если бы за этой командой сразу следовал end). Это связано с тем, что при возобновлении выполнения (даже с помощью простого next или step) вы можете столкнуться с другой точкой останова, которая может иметь свой собственный список команд, что приведет к неоднозначному пониманию того, какой список следует выполнить.

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

s(tep)

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

n(ext)

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

unt(il) [lineno]

Без аргумента продолжает выполнение до тех пор, пока не будет достигнута строка с номером, превышающим текущий.

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

Изменено в версии 3.2: Разрешите указывать явный номер строки.

r(eturn)

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

c(ont(inue))

Продолжайте выполнение, останавливаясь только при достижении точки останова.

j(ump) lineno

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

Следует отметить, что не все переходы разрешены - например, нельзя перейти в середину цикла for или из клаузулы finally.

l(ist) [first[, last]]

Вывести список исходного кода для текущего файла. Без аргументов перечислить 11 строк вокруг текущей строки или продолжить предыдущий листинг. С аргументом . перечислить 11 строк вокруг текущей строки. С одним аргументом - перечислить 11 строк вокруг этой строки. С двумя аргументами перечислить заданный диапазон; если второй аргумент меньше первого, он интерпретируется как счетчик.

Текущая строка в текущем кадре обозначается ->. Если отлаживается исключение, то строка, в которой оно было первоначально вызвано или распространено, обозначается >>, если она отличается от текущей строки.

Изменено в версии 3.2: Добавлен маркер >>.

ll | longlist

Вывести весь исходный код для текущей функции или кадра. Интересные строки помечены как для list.

Added in version 3.2.

a(rgs)

Выведите аргументы текущей функции и их текущие значения.

p expression

Оценить выражение в текущем контексте и вывести его значение.

Примечание

Можно также использовать print(), но это не команда отладчика - она выполняет функцию Python print().

pp expression

Как и команда p, за исключением того, что значение expression выводится с помощью модуля pprint.

whatis expression

Выведите тип выражения.

source expression

Попробуйте получить исходный код выражения и отобразить его.

Added in version 3.2.

display [expression]

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

Без выражения - список всех выражений отображения для текущего кадра.

Примечание

Дисплей оценивает выражение и сравнивает с результатом предыдущей оценки выражения, поэтому, когда результат изменяется, дисплей может не уловить изменения.

Пример:

lst = []
breakpoint()
pass
lst.append(1)
print(lst)

Дисплей не поймет, что lst был изменен, потому что результат оценки модифицируется на место lst.append(1) перед сравнением:

> example.py(3)<module>()
-> pass
(Pdb) display lst
display lst: []
(Pdb) n
> example.py(4)<module>()
-> lst.append(1)
(Pdb) n
> example.py(5)<module>()
-> print(lst)
(Pdb)

Вы можете проделать некоторые трюки с механизмом копирования, чтобы заставить его работать:

> example.py(3)<module>()
-> pass
(Pdb) display lst[:]
display lst[:]: []
(Pdb) n
> example.py(4)<module>()
-> lst.append(1)
(Pdb) n
> example.py(5)<module>()
-> print(lst)
display lst[:]: [1]  [old: []]
(Pdb)

Added in version 3.2.

undisplay [expression]

Больше не отображать выражение в текущем кадре. Без выражения очистить все отображаемые выражения для текущего кадра.

Added in version 3.2.

interact

Запуск интерактивного интерпретатора (с помощью модуля code) в новом глобальном пространстве имен, инициализированном из локального и глобального пространств имен для текущей области видимости. Используйте exit() или quit(), чтобы выйти из интерпретатора и вернуться в отладчик.

Примечание

Поскольку interact создает новое выделенное пространство имен для выполнения кода, присваивания переменным не будут влиять на исходные пространства имен. Однако модификации любых ссылающихся мутабельных объектов будут отражены в исходных пространствах имен, как обычно.

Added in version 3.2.

Изменено в версии 3.13: exit() и quit() можно использовать для выхода из команды interact.

Изменено в версии 3.13: interact направляет свой вывод на выходной канал отладчика, а не на sys.stderr.

alias [name [command]]

Создайте псевдоним name, который будет выполнять команду. Параметр команда не должен быть заключен в кавычки. Заменяемые параметры могут быть обозначены %1, %2, … и %9, а %* заменяется всеми параметрами. Если команда опущена, будет показан текущий псевдоним для имени. Если аргументы не указаны, будут перечислены все псевдонимы.

Псевдонимы могут быть вложенными и содержать все, что может быть набрано в приглашении pdb. Обратите внимание, что внутренние команды pdb могут быть переопределены псевдонимами. Такая команда будет скрыта до тех пор, пока псевдоним не будет удален. Псевдоним рекурсивно применяется к первому слову командной строки; все остальные слова в строке остаются без изменений.

В качестве примера можно привести два полезных псевдонима (особенно если поместить их в файл .pdbrc):

# Print instance variables (usage "pi classInst")
alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}")
# Print instance variables in self
alias ps pi self
unalias name

Удаление указанного псевдонима имя.

! statement

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

(Pdb) ! n=42
(Pdb)

Чтобы задать глобальную переменную, можно снабдить команду присваивания оператором global в той же строке, например:

(Pdb) global list_options; list_options = ['-l']
(Pdb)
run [args ...]
restart [args ...]

Перезапуск отлаживаемой программы Python. Если задан args, он разделяется с shlex, и результат используется как новый sys.argv. История, точки останова, действия и опции отладчика сохраняются. restart является псевдонимом для run.

q(uit)

Выход из отладчика. Выполняемая программа прерывается.

debug code

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

retval

Выведите значение последнего возврата текущей функции.

exceptions [excnumber]

Перечисление или переход между цепочками исключений.

При использовании pdb.pm() или Pdb.post_mortem(...) с цепочкой исключений вместо traceback, это позволяет пользователю перемещаться между цепочками исключений, используя команду exceptions для перечисления исключений и exception <number> для перехода к этому исключению.

Пример:

def out():
    try:
        middle()
    except Exception as e:
        raise ValueError("reraise middle() error") from e

def middle():
    try:
        return inner(0)
    except Exception as e:
        raise ValueError("Middle fail")

def inner(x):
    1 / x

 out()

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

> example.py(5)out()
-> raise ValueError("reraise middle() error") from e

(Pdb) exceptions
  0 ZeroDivisionError('division by zero')
  1 ValueError('Middle fail')
> 2 ValueError('reraise middle() error')

(Pdb) exceptions 0
> example.py(16)inner()
-> 1 / x

(Pdb) up
> example.py(10)middle()
-> return inner(0)

Added in version 3.13.

Сноски