Рубрики
Без рубрики

PDB – Интерактивный отладчик

Автор оригинала: Doug Hellmann.

Цель:

Интерактивный отладчик Python

<Код> PDB реализует интерактивную среду отладки для программ Python. Он включает в себя функции, чтобы приостановить программу, взглянуть на значения переменных и наблюдать за шагом выполнения программы, поэтому вы можете понять, какая программа на самом деле делает и находит ошибки в логике.

Начиная отладчик

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

Из командной строки

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

pdb_script.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#


class MyObj:

    def __init__(self, num_loops):
        self.count  num_loops

    def go(self):
        for i in range(self.count):
            print(i)
        return

if __name__  '__main__':
    MyObj(5).go()

Запуск отладчика из командной строки заставляет его загрузить исходный файл и остановить выполнение на первом утверждении, который он находит. В этом случае он останавливается перед оценкой определения класса <Код> Myobj на строке 8.

$ python3 -m pdb pdb_script.py

> .../pdb_script.py(8)()
-> class MyObj(object):
(Pdb)

Примечание

Обычно <Код> PDB включает полный путь к каждому модулю на выходе при печати имени файла. Чтобы поддерживать простые примеры, путь в выходе образца в этом разделе был заменен с помощью ELLIPSIS ( ... ).

В пределах переводчика

Многие разработчики Python работают с интерактивным интерпретатором при разработке ранних версий модулей, потому что он позволяет им более итеративно поэкспертисовать без цикла Save/Run/Repeate, необходимых при создании автономных скриптов. Чтобы запустить отладчик из Interactive интерпретатора, используйте RUN () или RUNEVAL () .

$ python3

Python 3.5.1 (v3.5.1:37a07cee5969, Dec  5 2015, 21:12:44)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb_script
>>> import pdb
>>> pdb.run('pdb_script.MyObj(5).go()')
> (1)()
(Pdb)

Аргумент для RUN () – это строковое выражение, которое может быть оценено переводчиком Python. Отладчик будет разбирать его, затем приостановить выполнение незадолго до оценки первого выражения. Описанные здесь команды отладчика могут использоваться для навигации и контроля выполнения.

Изнутри программы

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

pdb_set_trace.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#

import pdb


class MyObj:

    def __init__(self, num_loops):
        self.count  num_loops

    def go(self):
        for i in range(self.count):
            pdb.set_trace()
            print(i)
        return

if __name__  '__main__':
    MyObj(5).go()

Линия 17 образца сценария запускает отладчик в тот момент в исполнении, приостановив его на линии 18.

$ python3 ./pdb_set_trace.py

> .../pdb_set_trace.py(18)go()
-> print(i)
(Pdb)

SET_TRACE () – это просто функция Python, поэтому ее можно вызвать в любой точке в программе. Это позволяет вводить отладчик на основе условий внутри программы, в том числе из обработчика исключений или через определенную ветку оператора управления.

После провала

Отладка сбоя после завершения программы называется отладки . PDB Поддерживает отладку после истечения через <код> PM () и <код> post_mortem () .

pdb_post_mortem.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#


class MyObj:

    def __init__(self, num_loops):
        self.count  num_loops

    def go(self):
        for i in range(self.num_loops):
            print(i)
        return

Здесь неправильное имя атрибута в строке 14 вызывает <код> ATTATHUTEERROR исключение, вызывая остановку выполнения. <Код> PM () ищет активную трассировку и запускает отладчик в точке в стеке вызовов, где произошло исключение.

$ python3
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  5 2015, 21:12:44)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from pdb_post_mortem import MyObj
>>> MyObj(5).go()
Traceback (most recent call last):
  File "", line 1, in 
  File ".../pdb_post_mortem.py", line 14, in go
    for i in range(self.num_loops):
AttributeError: 'MyObj' object has no attribute 'num_loops'
>>> import pdb
>>> pdb.pm()
> .../pdb/pdb_post_mortem.py(14)go()
-> for i in range(self.num_loops):
(Pdb)

Контроль отладчика

Интерфейс для отладчика – это небольшой язык команд, который позволяет двигаться вокруг стека вызовов, изучить и изменять значения переменных и контролировать, как отладчик выполняет программу. Интерактивный отладчик использует readline для принятия команд и поддерживает завершение вкладки для команд, имена файлов и имен функций. Вход в пустую строку снова запускает предыдущую команду, если только это не было LIST .

Навигация на стек исполнения

В любой момент, когда отладчик работает, используйте <код> где (сокращенный <код> W ), чтобы точно выяснить, какую строку выполняются и где в стеке вызова программа. В этом случае модуль <код> PDB_SET_TRACE.PY LINE 18 в GO () метода.

$ python3 pdb_set_trace.py
> .../pdb_set_trace.py(18)go()
-> print(i)
(Pdb) where
  .../pdb_set_trace.py(22)()
-> MyObj(5).go()
> .../pdb_set_trace.py(18)go()
-> print(i)
(Pdb)

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

(Pdb) l
 13          self.count = num_loops
 14
 15      def go(self):
 16          for i in range(self.count):
 17              pdb.set_trace()
 18  ->          print(i)
 19          return
 20
 21  if __name__ == '__main__':
 22      MyObj(5).go()
[EOF]
(Pdb)

По умолчанию отображается 11 строк по текущей линии (пять до и пять после). Используя список с одним численным аргументом списков 11 строк вокруг этой строки вместо текущей строки.

(Pdb) list 14
  9
 10  class MyObj(object):
 11
 12      def __init__(self, num_loops):
 13          self.count = num_loops
 14
 15      def go(self):
 16          for i in range(self.count):
 17              pdb.set_trace()
 18  ->          print(i)
 19          return

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

(Pdb) list 7, 19
  7  import pdb
  8
  9
 10  class MyObj(object):
 11
 12      def __init__(self, num_loops):
 13          self.count = num_loops
 14
 15      def go(self):
 16          for i in range(self.count):
 17              pdb.set_trace()
 18  ->          print(i)
 19          return

longlist (<код> ll ) распечатывает источник для текущей функции или кадра, без необходимости заранее определения номеров строк. Команда «LongList», потому что для длительных функций она может производить значительно больше выходов, чем значение по умолчанию для LIST .

(Pdb) longlist
 15      def go(self):
 16          for i in range(self.count):
 17              pdb.set_trace()
 18  ->          print(i)
 19          return

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

(Pdb) source MyObj
 10  class MyObj:
 11
 12      def __init__(self, num_loops):
 13          self.count = num_loops
 14
 15      def go(self):
 16          for i in range(self.count):
 17              pdb.set_trace()
 18              print(i)
 19          return

Перемещение между кадрами в текущем стеке вызовов с использованием UP и DOWN . UP (сокращенный <код> U ) движется к старым рамам на стеке. <Код> вниз (<код> d ) движется к более новым рамам. Каждый раз, когда вы перемещаетесь вверх или вниз по стеку, отладчик печатает текущее местоположение в том же формате, что и производится <код> где .

(Pdb) up
> .../pdb_set_trace.py(22)()
-> MyObj(5).go()

(Pdb) down
> .../pdb_set_trace.py(18)go()
-> print(i)

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

Изучение переменных на стеке

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

pdb_function_arguments.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#

import pdb


def recursive_function(n5, output'to be printed'):
    if n > 0:
        recursive_function(n - 1)
    else:
        pdb.set_trace()
        print(output)
    return

if __name__  '__main__':
    recursive_function()

Команда ARGS (сокращенный <код> A ) распечатывает все аргументы функции, активную в текущем кадре. Этот пример также использует рекурсивную функцию, чтобы показать, как выглядит более глубокий стек, когда напечатано <код> где .

$ python3 pdb_function_arguments.py
> .../pdb_function_arguments.py(15)recursive_function()
-> print(output)
(Pdb) where
  .../pdb_function_arguments.py(19)()
-> recursive_function()
  .../pdb_function_arguments.py(12)recursive_function()
-> recursive_function(n - 1)
  .../pdb_function_arguments.py(12)recursive_function()
-> recursive_function(n - 1)
  .../pdb_function_arguments.py(12)recursive_function()
-> recursive_function(n - 1)
  .../pdb_function_arguments.py(12)recursive_function()
-> recursive_function(n - 1)
  .../pdb_function_arguments.py(12)recursive_function()
-> recursive_function(n - 1)
> .../pdb_function_arguments.py(15)recursive_function()
-> print(output)

(Pdb) args
n = 0
output = to be printed

(Pdb) up
> .../pdb_function_arguments.py(12)recursive_function()
-> recursive_function(n - 1)

(Pdb) args
n = 1
output = to be printed

Команда P оценивает выражение, приведенное в качестве аргумента и печатает результат. PRINT () PRINT () .

(Pdb) p n
1

(Pdb) print(n)
1

Точно так же префикс выражения <код>! передает его в переводчик Python, который должен быть оценен. Эта функция может быть использована для выполнения произвольных утверждений Python, включая изменение переменных. В этом примере меняется значение , прежде чем позволить отладчику продолжить работу программы. Следующее утверждение после вызова SET_TRACE () Распечатает значение Выход , показывающий модифицированное значение.

$ python3 pdb_function_arguments.py

> .../pdb_function_arguments.py(14)recursive_function()
-> print(output)

(Pdb) !output
'to be printed'

(Pdb)

(Pdb) continue
changed value

Для более сложных значений, таких как вложенные или большие структуры данных, используйте PP , чтобы «довольно печатать» их. Эта программа читает несколько строк текста из файла.

pdb_pp.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#

import pdb

with open('lorem.txt', 'rt') as f:
    lines  f.readlines()

pdb.set_trace()

Печать переменной <Код> Линии с <Код> P Приводит к выводу, который трудно прочитать, потому что он может отклониться от неловкого. <Код> PP Использует PPRINT для форматирования значения для чистой печати.

$ python3 pdb_pp.py

> .../pdb_pp.py(12)()->None
-> pdb.set_trace()
(Pdb) p lines
['Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
\n', 'Donec egestas, enim et consecte tuer ullamcorper, lect
us \n', 'ligula rutrum leo, a elementum el it tortor eu quam
.\n']

(Pdb) pp lines
['Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \n',
 'Donec egestas, enim et consectetuer ullamcorper, lectus \n',
 'ligula rutrum leo, a elementum elit tortor eu quam.\n']

(Pdb)

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

$ python3 -m pdb pdb_interact.py
> .../pdb_interact.py(7)()
-> import pdb
(Pdb) break 14
Breakpoint 1 at .../pdb_interact.py:14

(Pdb) continue
> .../pdb_interact.py(14)f()
-> print(l, m, n)

(Pdb) p l
['a', 'b']

(Pdb) p m
9

(Pdb) p n
5

(Pdb) interact
*interactive*

>>> l
['a', 'b']

>>> m
9

>>> n
5

Мулюбные объекты, такие как списки, могут быть изменены с интерактивного интерпретатора. Имена неизменных объектов не могут, а имена не могут быть отскорены к новым значениям.

>>> l.append('c')
>>> m
>>> n = 3

>>> l
['a', 'b', 'c']

>>> m
16

>>> n
3

Используйте последовательность конца файла Ctrl-D для выхода из интерактивной подсказки и вернитесь к отладчику. В этом примере список L был изменен, но значения <код> m и <код> n нет.

>>> ^D

(Pdb) p l
['a', 'b', 'c']

(Pdb) p m
9

(Pdb) p n
5

(Pdb)

Перейти через программу

В дополнение к навигации вверх и вниз по стеку вызовов, когда программа приостановлена, также можно выйти через выполнение программы за счет того, что она входит в отладчик.

pdb_step.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#

import pdb


def f(n):
    for i in range(n):
        j  i * n
        print(i, j)
    return

if __name__  '__main__':
    pdb.set_trace()
    f(5)

Используйте STEP (сокращенный <код> S ), чтобы выполнить текущую строку, а затем останавливаться на следующей точке выполнения – либо первое утверждение внутри вызываемой функции, либо следующей строки текущего функция.

$ python3 pdb_step.py

> .../pdb_step.py(18)()
-> f(5)

Переводчик делает паузы после вызова SET_TRACE () и дает элемент управления отладчиком. Первый этап <код> вызывает выполнение для ввода <код> f () .

(Pdb) step
--Call--
> .../pdb_step.py(10)f()
-> def f(n):

Еще один <код> step перемещает выполнение в первой строке f () и запускает цикл.

(Pdb) step
> .../pdb_step.py(11)f()
-> for i in range(n):

Шагпинг снова перемещается к первой строке внутри цикла, где определяется <код> j .

(Pdb) step
> .../pdb_step.py(12)f()
-> j = i * n

(Pdb) p i
0

Значение i есть <код> 0 , поэтому после еще одного шага Значение J также должно быть <код> 0 .

(Pdb) step
> .../pdb_step.py(13)f()
-> print(i, j)

(Pdb) p j
0

(Pdb)

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

pdb_next.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#

import pdb


def calc(i, n):
    j  i * n
    return j


def f(n):
    for i in range(n):
        j  calc(i, n)
        print(i, j)
    return

if __name__  '__main__':
    pdb.set_trace()
    f(5)

В этом примере нет ничего плохого в CALC () , так что наступив через него каждый раз, когда он вызывается в цикле в <Код> F () скрывает полезный вывод, показывая все Из строк Calc () как они выполняются.

$ python3 pdb_next.py

> .../pdb_next.py(23)()
-> f(5)
(Pdb) step
--Call--
> .../pdb_next.py(15)f()
-> def f(n):

(Pdb) step
> .../pdb_next.py(16)f()
-> for i in range(n):

(Pdb) step
> .../pdb_next.py(17)f()
-> j = calc(i, n)

(Pdb) step
--Call--
> .../pdb_next.py(10)calc()
-> def calc(i, n):

(Pdb) step
> .../pdb_next.py(11)calc()
-> j = i * n

(Pdb) step
> .../pdb_next.py(12)calc()
-> return j

(Pdb) step
--Return--
> .../pdb_next.py(12)calc()->0
-> return j

(Pdb) step
> .../pdb_next.py(18)f()
-> print(i, j)

(Pdb) step
0 0

> .../pdb_next.py(16)f()
-> for i in range(n):
(Pdb)

NEXT COMMENT (сокращенный <код> N ) похож на шаг <код> , но не входит в функции, вызываемые из оператора. По сути, он выполняется до конца вызова функции к следующему оператору в текущей функции в одном операции.

> .../pdb_next.py(16)f()
-> for i in range(n):
(Pdb) step
> .../pdb_next.py(17)f()
-> j = calc(i, n)

(Pdb) next
> .../pdb_next.py(18)f()
-> print(i, j)

(Pdb)

до команды next , за исключением его явно продолжается до тех пор, пока выполнение не достигнет строки в той же функции с числом строки выше текущего значения. Это означает, например, что <код> до может быть использован для шаги за конец контура.

$ python3 pdb_next.py

> .../pdb_next.py(23)()
-> f(5)
(Pdb) step
--Call--
> .../pdb_next.py(15)f()
-> def f(n):

(Pdb) step
> .../pdb_next.py(16)f()
-> for i in range(n):

(Pdb) step
> .../pdb_next.py(17)f()
-> j = calc(i, n)

(Pdb) next
> .../pdb_next.py(18)f()
-> print(i, j)

(Pdb) until
0 0
1 5
2 10
3 15
4 20
> .../pdb_next.py(19)f()
-> return

(Pdb)

До того, как команда до текущая строка составляла 18, последнюю строку цикла. После до Ran выполнение было в строке 19, а цикл был исчерпан.

Чтобы выполнить выполнение до определенной строки, пропустите номер строки в команду <код> до . В отличие от установки точки останова, номер линии передал <код> до , должен быть выше текущего номера строки, поэтому наиболее полезно для навигации в функции для пропускания длинных блоков.

$ python3 pdb_next.py
> .../pdb_next.py(23)()
-> f(5)
(Pdb) list
 18          print(i, j)
 19      return
 20
 21  if __name__ == '__main__':
 22      pdb.set_trace()
 23  ->    f(5)
[EOF]

(Pdb) until 18
*** "until" line number is smaller than current line number

(Pdb) step
--Call--
> .../pdb_next.py(15)f()
-> def f(n):

(Pdb) step
> .../pdb_next.py(16)f()
-> for i in range(n):

(Pdb) list
 11      j = i * n
 12      return j
 13
 14
 15  def f(n):
 16  ->    for i in range(n):
 17          j = calc(i, n)
 18          print(i, j)
 19      return
 20
 21  if __name__ == '__main__':

(Pdb) until 19
0 0
1 5
2 10
3 15
4 20
> .../pdb_next.py(19)f()
-> return

(Pdb)

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

$ python3 pdb_next.py

> .../pdb_next.py(23)()
-> f(5)
(Pdb) step
--Call--
> .../pdb_next.py(15)f()
-> def f(n):

(Pdb) step
> .../pdb_next.py(16)f()
-> for i in range(n):

(Pdb) return
0 0
1 5
2 10
3 15
4 20
--Return--
> .../pdb_next.py(19)f()->None
-> return

(Pdb)

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

Поскольку программы растут дольше, даже используя <код> следующий и <код> до не станут медленными и громоздкими. Вместо того, чтобы выйти через программу вручную, лучшее решение для того, чтобы он проводился нормально, пока он не достигнет точки, где отладчик должен прерывать его. SET_TRACE () может запустить отладчик, но это работает только в том случае, если в программе есть одна точка, в которой она должна пауза. Удобнее запустить программу через отладчик, но сообщите отладку, где заранее останавливаться, используя точку останова . Отладчик контролирует программу, и когда она достигает местоположения, описанного точкой останова, программа приостановлена до выполнения строки.

pdb_break.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#


def calc(i, n):
    j  i * n
    print('j =', j)
    if j > 0:
        print('Positive!')
    return j


def f(n):
    for i in range(n):
        print('i =', i)
        j  calc(i, n)  # noqa
    return

if __name__  '__main__':
    f(5)

Существует несколько вариантов для команды Break (сокращенный <код> b ), используемый для настройки точек перерыва, включая номер строки, файла и функцию, где обработка должна пауза. Чтобы установить точку останова на определенную строку текущего файла, используйте BRAW LINENO .

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 12
Breakpoint 1 at .../pdb_break.py:12

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb_break.py(12)calc()
-> print('Positive!')

(Pdb)

Команда Продолжить (сокращенный <код> C ) сообщает отладчик, чтобы продолжать запустить программу до следующей точки останова. В этом случае он проходит через первую итерацию LOOP для LOOP F () и останавливается внутри CALC () во время второй итерации.

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

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:8

(Pdb) continue
i = 0
> .../pdb_break.py(9)calc()
-> j = i * n

(Pdb) where
  .../pdb_break.py(23)()
-> f(5)
  .../pdb_break.py(19)f()
-> j = calc(i, n)
> .../pdb_break.py(9)calc()
-> j = i * n

(Pdb)

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

pdb_break_remote.py

1
2
3
4
5
6
#!/usr/bin/env python3
# encoding: utf-8

from pdb_break import f

f(5)

Здесь точка останова установлена на строку 12 <Код> PDB_Break.py После запуска основной программы <Код> PDB_Break_Remote.py .

$ python3 -m pdb pdb_break_remote.py

> .../pdb_break_remote.py(4)()
-> from pdb_break import f
(Pdb) break pdb_break.py:12
Breakpoint 1 at .../pdb_break.py:12

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb_break.py(12)calc()
-> print('Positive!')

(Pdb)

Имя файла может быть полным путем к исходным файлам или относительному пути к файлу, доступному на Sys.Path .

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

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 12
Breakpoint 1 at .../pdb_break.py:12

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:12

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb/pdb_break.py(12)calc()
-> print('Positive!')

(Pdb) continue
Positive!
i = 2
j = 10
> .../pdb_break.py(12)calc()
-> print('Positive!')

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:12
        breakpoint already hit 2 times

(Pdb)

Управление точками останова

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

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:8

(Pdb) break 12
Breakpoint 2 at .../pdb_break.py:12

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:8
2   breakpoint   keep yes   at .../pdb_break.py:12

(Pdb) disable 1

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep no    at .../pdb_break.py:8
2   breakpoint   keep yes   at .../pdb_break.py:12

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb_break.py(12)calc()
-> print('Positive!')

(Pdb)

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

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:8

(Pdb) break 18
Breakpoint 2 at .../pdb_break.py:18

(Pdb) disable 1

(Pdb) continue
> .../pdb_break.py(18)f()
-> print('i =', i)

(Pdb) list
 13      return j
 14
 15
 16  def f(n):
 17      for i in range(n):
 18 B->      print('i =', i)
 19          j = calc(i, n)
 20      return
 21
 22  if __name__ == '__main__':
 23      f(5)

(Pdb) continue
i = 0
j = 0
> .../pdb_break.py(18)f()
-> print('i =', i)

(Pdb) list
 13      return j
 14
 15
 16  def f(n):
 17      for i in range(n):
 18 B->      print('i =', i)
 19          j = calc(i, n)
 20      return
 21
 22  if __name__ == '__main__':
 23      f(5)

(Pdb) p i
 1

(Pdb) enable 1
Enabled breakpoint 1 at .../pdb_break.py:8

(Pdb) continue
i = 1
> .../pdb_break.py(9)calc()
-> j = i * n

(Pdb) list
  4  # Copyright (c) 2010 Doug Hellmann.  All rights reserved.
  5  #
  6
  7
  8 B   def calc(i, n):
  9  ->    j = i * n
 10        print('j =', j)
 11        if j > 0:
 12            print('Positive!')
 13        return j
 14

(Pdb)

Линии, префиксированные B в выходе из List Show, где установлены точки останова в программе (строки 8 и 18).

Используйте CLEAR Чтобы исключить точку останова.

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:8

(Pdb) break 12
Breakpoint 2 at .../pdb_break.py:12

(Pdb) break 18
Breakpoint 3 at .../pdb_break.py:18

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:8
2   breakpoint   keep yes   at .../pdb_break.py:12
3   breakpoint   keep yes   at .../pdb_break.py:18

(Pdb) clear 2
Deleted breakpoint 2

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:8
3   breakpoint   keep yes   at .../pdb_break.py:18

(Pdb)

Другие точки останова сохраняют свои первоначальные идентификаторы и не перенумерованы.

Временные точки останова

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

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) tbreak 12
Breakpoint 1 at .../pdb_break.py:12

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
Deleted breakpoint 1 at .../pdb_break.py:12
> .../pdb_break.py(12)calc()
-> print('Positive!')

(Pdb) break

(Pdb) continue
Positive!
i = 2
j = 10
Positive!
i = 3
j = 15
Positive!
i = 4
j = 20
Positive!
The program finished and will be restarted
> .../pdb_break.py(8)()
-> def calc(i, n):

(Pdb)

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

Условные точки останова

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

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 10, j>0
Breakpoint 1 at .../pdb_break.py:10

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:10
        stop only if j>0

(Pdb) continue
i = 0
j = 0
i = 1
> .../pdb_break.py(10)calc()
-> print('j =', j)

(Pdb)

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

Условие также может быть применено к существующей точке останова, используя команду <код> . Аргументы – это идентификатор точки останова и выражение.

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 10
Breakpoint 1 at .../pdb_break.py:10

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:10

(Pdb) condition 1 j>0

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:10
        stop only if j>0

(Pdb)

Игнорирование точек останова

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

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 19
Breakpoint 1 at .../pdb_break.py:19

(Pdb) continue
i = 0
> .../pdb_break.py(19)f()
-> j = calc(i, n)

(Pdb) next
j = 0
> .../pdb_break.py(17)f()
-> for i in range(n):

(Pdb) ignore 1 2
Will ignore next 2 crossings of breakpoint 1.

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:19
        ignore next 2 hits
        breakpoint already hit 1 time

(Pdb) continue
i = 1
j = 5
Positive!
i = 2
j = 10
Positive!
i = 3
> .../pdb_break.py(19)f()
-> j = calc(i, n)

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:19
        breakpoint already hit 4 times

Явное сброс счета игнорирования до нуля Re-позволяет немедленно включить точку останова.

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 19
Breakpoint 1 at .../pdb_break.py:19

(Pdb) ignore 1 2
Will ignore next 2 crossings of breakpoint 1.

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:19
        ignore next 2 hits

(Pdb) ignore 1 0
Will stop next time breakpoint 1 is reached.

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_break.py:19

Запуск действий на точке останова

В дополнение к чисто интерактивному режиму <код> PDB поддерживает базовые сценарии. Использование команд , ряд команд интерпретатора, включая операторы Python, могут быть выполнены, когда встречается определенная точка останова. После запуска команд с номером точки останова в качестве аргумента, подсказки отладчика изменяется в (COM) . Введите команды одновременно и закончите список с помощью End , чтобы сохранить скрипт и вернуться к главной подсказке отладчика.

$ python3 -m pdb pdb_break.py

> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 10
Breakpoint 1 at .../pdb_break.py:10

(Pdb) commands 1
(com) print('debug i =', i)
(com) print('debug j =', j)
(com) print('debug n =', n)
(com) end

(Pdb) continue
i = 0
debug i = 0
debug j = 0
debug n = 5
> .../pdb_break.py(10)calc()
-> print('j =', j)

(Pdb) continue
j = 0
i = 1
debug i = 1
debug j = 5
debug n = 5
> .../pdb_break.py(10)calc()
-> print 'j =', j

(Pdb)

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

Наблюдение за изменением данных

Также можно посмотреть как изменение значений в ходе выполнения программы без сценариев явного <Кода> Печать Commands, используя команду <код> .

$ python3 -m pdb pdb_break.py
> .../pdb_break.py(8)()
-> def calc(i, n):
(Pdb) break 18
Breakpoint 1 at .../pdb_break.py:18

(Pdb) continue
> .../pdb_break.py(18)f()
-> print('i =', i)

(Pdb) display j
display j: ** raised NameError: name 'j' is not defined **

(Pdb) next
i = 0
> .../pdb_break.py(19)f()
-> j = calc(i, n)  # noqa

(Pdb) next
j = 0
> .../pdb_break.py(17)f()
-> for i in range(n):
display j: 0  [old: ** raised NameError: name 'j' is not defined **]

(Pdb)

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

(Pdb) display
Currently displaying:
j: 0

(Pdb) up
> .../pdb_break.py(23)()
-> f(5)

(Pdb) display
Currently displaying:

(Pdb)

Удалите выражение дисплея <код> Undisplay .

(Pdb) display
Currently displaying:
j: 0

(Pdb) undisplay j

(Pdb) display
Currently displaying:

(Pdb)

Изменение потока выполнения

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

pdb_jump.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#


def f(n):
    result  []
    j  0
    for i in range(n):
        j  i * n + j
        j  n
        result.append(j)
    return result

if __name__  '__main__':
    print(f(5))

При запуске без вмешательства Вывод – это последовательность растущих чисел, деливых по <код> 5 .

$ python3 pdb_jump.py

[5, 15, 30, 50, 75]

Прыгать вперед

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

$ python3 -m pdb pdb_jump.py

> .../pdb_jump.py(8)()
-> def f(n):
(Pdb) break 13
Breakpoint 1 at .../pdb_jump.py:13

(Pdb) continue
> .../pdb_jump.py(13)f()
-> j

(Pdb) p j
0

(Pdb) step
> .../pdb_jump.py(14)f()
-> result.append(j)

(Pdb) p j
5

(Pdb) continue
> .../pdb_jump.py(13)f()
-> j

(Pdb) jump 14
> .../pdb_jump.py(14)f()
-> result.append(j)

(Pdb) p j
10

(Pdb) disable 1

(Pdb) continue
[5, 10, 25, 45, 70]

The program finished and will be restarted
> .../pdb_jump.py(8)()
-> def f(n):
(Pdb)

Отпрыгивать

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

$ python3 -m pdb pdb_jump.py

> .../pdb_jump.py(8)()
-> def f(n):
(Pdb) break 14
Breakpoint 1 at .../pdb_jump.py:14

(Pdb) continue
> .../pdb_jump.py(14)f()
-> result.append(j)

(Pdb) p j
5

(Pdb) jump 13
> .../pdb_jump.py(13)f()
-> j

(Pdb) continue
> .../pdb_jump.py(14)f()
-> result.append(j)

(Pdb) p j
10

(Pdb) disable 1

(Pdb) continue
[10, 20, 35, 55, 80]

The program finished and will be restarted
> .../pdb_jump.py(8)()
-> def f(n):
(Pdb)

Незаконные прыжки

Переход в определенные операторы управления потоками опасны или не определены и поэтому не допускаются отладчиком.

pdb_no_jump.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#


def f(n):
    if n < 0:
        raise ValueError('Invalid n: {}'.format(n))
    result  []
    j  0
    for i in range(n):
        j  i * n + j
        j  n
        result.append(j)
    return result


if __name__  '__main__':
    try:
        print(f(5))
    finally:
        print('Always printed')

    try:
        print(f(-5))
    except:
        print('There was an error')
    else:
        print('There was no error')

    print('Last statement')

<Код> Jump можно использовать для ввода функции, но аргументы не определены, и код вряд ли будет работать.

$ python3 -m pdb pdb_no_jump.py

> .../pdb_no_jump.py(8)()
-> def f(n):
(Pdb) break 22
Breakpoint 1 at .../pdb_no_jump.py:22

(Pdb) jump 9
> .../pdb_no_jump.py(9)()
-> if n < 0:

(Pdb) p n
*** NameError: NameError("name 'n' is not defined",)

(Pdb) args

(Pdb)

<Код> Jump не будет вводить в середину блока, такого как <код> для LOOP или TRY: кроме оператора.

$ python3 -m pdb pdb_no_jump.py

> .../pdb_no_jump.py(8)()
-> def f(n):
(Pdb) break 22
Breakpoint 1 at .../pdb_no_jump.py:22

(Pdb) continue
> .../pdb_no_jump.py(22)()
-> print(f(5))

(Pdb) jump 27
*** Jump failed: can't jump into the middle of a block

(Pdb)

Код в <Код> Наконец Block должен быть выполнен, поэтому Jump не оставит блок.

$ python3 -m pdb pdb_no_jump.py

> .../pdb_no_jump.py(8)()
-> def f(n):
(Pdb) break 24
Breakpoint 1 at .../pdb_no_jump.py:24

(Pdb) continue
[5, 15, 30, 50, 75]
> .../pdb_no_jump.py(24)()
-> print 'Always printed'

(Pdb) jump 26
*** Jump failed: can't jump into or out of a 'finally' block

(Pdb)

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

$ python3 -m pdb pdb_no_jump.py

> .../pdb_no_jump.py(8)()
-> def f(n):
(Pdb) break 12
Breakpoint 1 at .../pdb_no_jump.py:12

(Pdb) continue
> .../pdb_no_jump.py(12)f()
-> j = 0

(Pdb) where
  .../lib/python3.5/bdb.py(
431)run()
-> exec cmd in globals, locals
  (1)()
  .../pdb_no_jump.py(22)()
-> print(f(5))
> .../pdb_no_jump.py(12)f()
-> j = 0

(Pdb) up
> .../pdb_no_jump.py(22)()
-> print(f(5))

(Pdb) jump 25
*** You can only jump within the bottom frame

(Pdb)

Перезапуск программы

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

pdb_run.py

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/usr/bin/env python3
# encoding: utf-8
#
# Copyright (c) 2010 Doug Hellmann.  All rights reserved.
#

import sys


def f():
    print('Command-line args:', sys.argv)
    return

if __name__  '__main__':
    f()

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

$ python3 -m pdb pdb_run.py

> .../pdb_run.py(7)()
-> import sys
(Pdb) continue

Command line args: ['pdb_run.py']
The program finished and will be restarted
> .../pdb_run.py(7)()
-> import sys

(Pdb)

Программа может быть перезапущена с помощью Run . Аргументы, переданные в RUN проанализированы с помощью Chlex и передаются в программу, как будто они были аргументами командной строки, поэтому программа может быть перезапущена с разными настройками.

(Pdb) run a b c "this is a long value"
Restarting pdb_run.py with arguments:
        a b c this is a long value
> .../pdb_run.py(7)()
-> import sys

(Pdb) continue
Command line args: ['pdb_run.py', 'a', 'b', 'c',
'this is a long value']
The program finished and will be restarted
> .../pdb_run.py(7)()
-> import sys

(Pdb)

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

$ python3 -m pdb pdb_run.py

> .../pdb_run.py(7)()
-> import sys
(Pdb) break 11
Breakpoint 1 at .../pdb_run.py:11

(Pdb) continue
> .../pdb_run.py(11)f()
-> print('Command line args:', sys.argv)

(Pdb) run one two three
Restarting pdb_run.py with arguments:
        one two three
> .../pdb_run.py(7)()
-> import sys

(Pdb)

Настройка отладчика с псевдонимами

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

$ python3 -m pdb pdb_function_arguments.py

> .../pdb_function_arguments.py(7)()
-> import pdb
(Pdb) break 11
Breakpoint 1 at .../pdb_function_arguments.py:11

(Pdb) continue
> .../pdb_function_arguments.py(11)recursive_function()
-> if n > 0:

(Pdb) pp locals().keys()
dict_keys(['output', 'n'])

(Pdb) alias pl pp locals().keys()

(Pdb) pl
dict_keys(['output', 'n'])

Бег <код> псевдоним без каких-либо аргументов показывает список определенных псевдонимов. Предполагается, что один аргумент является именем псевдонима, и его определение напечатано.

(Pdb) alias
pl = pp locals().keys()

(Pdb) alias pl
pl = pp locals().keys()

(Pdb)

Аргументы псевдоним ссылаются с использованием <код>% N , где <код> n заменяется числом, указывающим положение аргумента, начиная с <код> 1 . Чтобы потреблять все аргументы, используйте <Код>% * .

$ python3 -m pdb pdb_function_arguments.py

> .../pdb_function_arguments.py(7)()
-> import pdb
(Pdb) alias ph !help(%1)

(Pdb) ph locals
Help on built-in function locals in module builtins:

locals()
    Return a dictionary containing the current scope's local
    variables.

    NOTE: Whether or not updates to this dictionary will affect
    name lookups in the local scope and vice-versa is
    *implementation dependent* and not covered by any backwards
    compatibility guarantees.

Очистить определение псевдонима с UNALIAS .

(Pdb) unalias ph

(Pdb) ph locals
*** SyntaxError: invalid syntax (, line 1)

(Pdb)

Сохранение настроек конфигурации

Отладка программы включает в себя много повторений: запустить код, наблюдая за выходом, регулировка кода или входов и снова запущена. <Код> PDB Попытки сократить объем повторения, необходимого для управления опытом отладки, чтобы позволить вам сконцентрироваться на коде вместо отладчика. Чтобы помочь уменьшить количество раз, когда вы выпускаете те же команды для отладчика, <Код> PDB можно прочитать сохраненную конфигурацию из текстовых файлов, интерпретируемых, как она начинается.

Файл <код> ~/.pdbrc Сначала прочитал, что позволяет глобальным личным предпочтениям для всех сеансов отладки. Тогда <код> ./. PDBRC читается из текущего рабочего каталога, чтобы установить локальные настройки для определенного проекта.

$ cat ~/.pdbrc

# Show python help
alias ph !help(%1)
# Overridden alias
alias redefined p 'home definition'

$ cat .pdbrc

# Breakpoints
break 11
# Overridden alias
alias redefined p 'local definition'

$ python3 -m pdb pdb_function_arguments.py

Breakpoint 1 at .../pdb_function_arguments.py:11
> .../pdb_function_arguments.py(7)()
-> import pdb
(Pdb) alias
ph = !help(%1)
redefined = p 'local definition'

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at .../pdb_function_arguments.py:11

(Pdb)

Любые команды конфигурации, которые можно набрать в командной строке отладчика, можно сохранить в одном из запуска файлов. Некоторые команды, которые управляют выполнением (<код> продолжить , <код> следующий и т. Д.) Также может.

$ cat .pdbrc
break 11
continue
list

$ python3 -m pdb pdb_function_arguments.py
Breakpoint 1 at .../pdb_function_arguments.py:11
  6
  7  import pdb
  8
  9
  10  def):
  11 B->    if n > 0:
  12            recursive_function(n - 1)
  13        else:
  14            pdb.set_trace()
  15            print(output)
  16        return
> .../pdb_function_arguments.py(11)recursive_function()
-> if n > 0:
(Pdb)

Особенно полезным является <код> RUN , что означает, что аргументы командной строки для сеанса отладки могут быть установлены в ./. PDBRC поэтому они согласуются на несколько прогонов.

$ cat .pdbrc
run a b c "long argument"

$ python3 -m pdb pdb_run.py
Restarting pdb_run.py with arguments:
      a b c "long argument"
> .../pdb_run.py(7)()
-> import sys

(Pdb) continue
Command-line args: ['pdb_run.py', 'a', 'b', 'c',
'long argument']
The program finished and will be restarted
> .../pdb_run.py(7)()
-> import sys

(Pdb)

Смотрите также

  • Стандартная библиотечная документация для PDB
  • readline – интерактивная библиотека для редактирования подсказки.
  • CMD – строить интерактивные программы.
  • Shupp – Shell командная строка разборки.
  • Python Neumpeate 26053 – если вывод Run не соответствует значениям, представленным здесь, обратитесь к этой ошибке Для получения подробной информации о регрессии в формате PDB от 2,7 до 3,5.