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

Отладка приложений Python с помощью модуля PDB

Автор оригинала: Muhammad Junaid Khalid.

Вступление

В этом уроке мы узнаем, как использовать модуль Python PDB для отладки приложений Python. Отладка относится к процессу удаления программных и аппаратных ошибок из программного приложения. PDB расшифровывается как “Python Debugger” и представляет собой встроенный интерактивный отладчик исходного кода с широким спектром функций, таких как приостановка программы, просмотр значений переменных в определенных экземплярах, изменение этих значений и т. Д.

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

Фон

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

Существует множество различных способов отладки программного приложения. Очень часто используемый метод использует операторы “print” в разных экземплярах вашего кода, чтобы увидеть, что происходит во время выполнения. Однако этот метод имеет много проблем, таких как добавление дополнительного кода, который используется для печати значений переменных и т. Д. Хотя этот подход может работать для небольшой программы, отслеживание этих изменений кода в большом приложении с большим количеством строк кода, разбросанных по разным файлам, может стать огромной проблемой. Отладчик решает эту проблему за нас. Это помогает нам найти источники ошибок в приложении с помощью внешних команд, поэтому никаких изменений в коде нет.

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

Ключевые команды

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

# Filename: calc.py

operators = ['+', '-', '*', '/']
numbers = [10, 20]

def calculator():
    print("Operators available: ")
    for op in operators:
        print(op)

    print("Numbers to be used: ")
    for num in numbers:
        print(num)

def main():
    calculator()

main()

Вот вывод скрипта выше:

Operators available:
+
-
*
/
Numbers to be used:
10
20

Я не добавил никаких комментариев в вышеприведенный код, так как он удобен для начинающих и не включает в себя никаких сложных концепций или синтаксиса вообще. Не важно пытаться понять “задачу”, которую выполняет этот код, поскольку его цель состояла в том, чтобы включить определенные вещи, чтобы все команды PDB могли быть протестированы на нем. Ладно, тогда начнем!

Использование PDB требует использования интерфейса командной строки (CLI), поэтому вам придется запускать приложение из терминала или командной строки.

Выполните приведенную ниже команду в вашем CLI:

$ python -m pdb calc.py

В приведенной выше команде мой файл называется “calc.py”, поэтому вам нужно будет вставить здесь свое собственное имя файла.

Примечание : - m – это флаг, и он уведомляет исполняемый файл Python о необходимости импорта модуля; за этим флагом следует имя модуля, которое в нашем случае является pdb .

Вывод команды выглядит следующим образом:

> /Users/junaid/Desktop/calc.py(3)()
-> operators = [ '+', '-', '*', '/' ]
(Pdb)

Выходные данные всегда будут иметь одну и ту же структуру. Он будет начинаться с пути к каталогу нашего файла исходного кода. Затем в скобках будет указан номер строки из того файла, на который в данный момент указывает PDB, который в нашем случае является “(3)”. Следующая строка, начинающаяся с символа” ->”, указывает на линию, на которую в данный момент указывают.

Чтобы закрыть приглашение PDB, просто введите quit или exit в приглашении PDB.

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

$ python -m pdb calc.py var1 var2 var3

Двигаясь дальше, если вы ранее закрыли приглашение PDB с помощью команды quit или exit , то повторно запустите файл кода через PDB. После этого выполните следующую команду в командной строке PDB:

(Pdb) list

Вывод выглядит следующим образом:

  1     # Filename: calc.py
  2
  3  -> operators = ['+', '-', '*', '/']
  4     numbers = [10, 20]
  5
  6     def calculator():
  7         print("Operators available: ")
  8         for op in operators:
  9             print(op)
 10
 11         print("Numbers to be used: ")
(Pdb)

Это покажет вам первые 11 строк вашей программы, а “->” будет указывать на текущую строку, выполняемую отладчиком. Затем попробуйте выполнить эту команду в командной строке PDB:

(Pdb) list 4,6

Эта команда должна отображать только выбранные строки, которые в данном случае являются строками с 4 по 6. Вот результат:

  4     numbers = [10, 20]
  5
  6     def calculator():
(Pdb)

Отладка с точками останова

Следующая важная вещь, о которой мы узнаем, – это точка останова. Точки останова обычно используются для больших программ, но чтобы лучше понять их, мы посмотрим, как они работают на нашем базовом примере. Точки останова-это определенные местоположения, которые мы объявляем в нашем коде. Наш код работает до этого места, а затем останавливается. Этим точкам автоматически присваиваются номера PDB.

У нас есть следующие различные варианты создания точек останова:

  1. По номеру строки
  2. По объявлению функции
  3. По условию

Чтобы объявить точку останова по номеру строки, выполните следующую команду в командной строке PDB:

(Pdb) break calc.py:8

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

Breakpoint 1 at /Users/junaid/Desktop/calc.py: 8
(Pdb)

Чтобы объявить точки останова функции, выполните следующую команду в командной строке PDB:

(Pdb) break calc.calculator

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

Breakpoint 2 at /Users/junaid/Desktop/calc.py:6

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

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

(Pdb) break calc.py:8, op == "*"

Это будет отслеживать значение переменной op на протяжении всего выполнения и прерываться только тогда, когда ее значение равно “*” в строке 8.

Чтобы увидеть все точки останова, которые мы объявили в виде списка, выполните следующую команду в командной строке PDB:

(Pdb) break

Вывод выглядит следующим образом:

Num Type         Disp Enb   Where
1   breakpoint   keep yes   at /Users/junaid/Desktop/calc.py: 8
2   breakpoint   keep yes   at /Users/junaid/Desktop/calc.py: 6
    breakpoint already hit 1 time
3   breakpoint   keep yes   at /Users/junaid/Desktop/calc.py: 8
    stop only if op == "*"
(Pdb)

Наконец, давайте посмотрим, как мы можем отключить, включить и очистить определенную точку останова в любом случае. Выполните следующую команду в командной строке PDB:

(Pdb) disable 2

Это отключит точку останова 2, но не удалит ее из нашего экземпляра отладчика.

В выходных данных вы увидите номер отключенной точки останова.

Disabled breakpoint 2 at /Users/junaid/Desktop/calc.py:6
(Pdb)

Давайте еще раз распечатаем список всех точек останова, чтобы увидеть значение “End” для точки останова 2:

(Pdb) break

Выход:

Num Type         Disp Enb   Where
1   breakpoint   keep yes   at /Users/junaid/Desktop/calc.py:8
2   breakpoint   keep no    at /Users/junaid/Desktop/calc.py:4 # you can see here that the "ENB" column for #2 shows "no"
    breakpoint already hit 1 time
3   breakpoint   keep yes   at /Users/junaid/Desktop/calc.py:8
    stop only if op == "*"
(Pdb)

Чтобы снова включить точку останова 2, выполните следующую команду:

(Pdb) enable 2

И опять же, вот результат:

Enabled breakpoint 2 at /Users/junaid/Desktop/calc.py:6

Теперь, если вы снова распечатаете список всех точек останова , значение столбца “Enb” для точки останова 2 должно снова показать “еще”.

Давайте теперь очистим точку останова 1, которая удалит все это вместе.

(Pdb) clear 1

Результат выглядит следующим образом:

Deleted breakpoint 1 at /Users/junaid/Desktop/calc.py:8
(Pdb)

Если мы перепечатаем список точек останова, то теперь он должен показывать только две строки точек останова. Давайте посмотрим на вывод команды “break”:

Num Type         Disp Enb   Where
2   breakpoint   keep yes   at /Users/junaid/Desktop/calc.py:4
    breakpoint already hit 1 time
3   breakpoint   keep yes   at /Users/junaid/Desktop/calc.py:8
    stop only if op == "*"

Именно этого мы и ожидали.

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

1. Очистите все точки останова

(Pdb) clear

После этого введите “y” и нажмите “Enter”. Вы должны увидеть такой вывод:

Deleted breakpoint 2 at /Users/junaid/Desktop/calc.py:6
Deleted breakpoint 3 at /Users/junaid/Desktop/calc.py:8

2. Объявите новую точку останова

Мы хотим добиться того, чтобы код выполнялся до тех пор, пока значение переменной num не станет больше 10. Таким образом, в принципе, программа должна сделать паузу до того, как будет напечатано число “20”.

(Pdb) break calc.py:13, num > 10

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

Чтобы запустить код, используйте команду “продолжить”, которая будет выполнять код до тех пор, пока он не достигнет точки останова или не завершится:

(Pdb) continue

Вы должны увидеть следующий вывод:

Operators available:
+
-
*
/
Numbers to be used:
10
> /Users/junaid/Desktop/calc.py(13)calculator()
-> print(num)

Это именно то, что мы ожидали, программа работает до этого момента, а затем останавливается, теперь это зависит от нас, если мы хотим что-то изменить, проверить переменные или если мы хотим запустить сценарий до завершения. Чтобы проинструктировать его работать до завершения, снова выполните команду “продолжить”. Результат должен быть следующим:

20
The program finished and will be restarted
> /Users/junaid/Desktop/calc.py(3)()
-> operators = [ '+', '-', '*', '/' ]

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

Важное примечание : Прежде чем двигаться вперед, очистите все точки останова, выполнив команду “очистить”, а затем набрав “y” в командной строке PDB.

Функции Next и Step

И последнее, но не менее важное: давайте изучим функции next и step ; они будут очень часто использоваться, когда вы начнете отлаживать свои приложения, поэтому давайте узнаем, что они делают и как их можно реализовать.

Функции step и next используются для итерации по всему нашему коду строка за строкой; между ними очень мало разницы. Во время итерации, если функция step столкнется с вызовом функции, она перейдет к первой строке определения этой функции и покажет нам точно, что происходит внутри функции; тогда как, если функция next столкнется с вызовом функции, она запустит все строки этой функции за один раз и остановится при следующем вызове функции.

Запутался? Давайте рассмотрим это на примере.

Повторно запустите программу через приглашение PDB, используя следующую команду:

$ python -m pdb calc.py

Теперь введите continue в приглашении PDB и продолжайте делать это до тех пор, пока программа не дойдет до конца. Ниже я покажу часть всей последовательности ввода и вывода, которой достаточно, чтобы объяснить суть. Полная последовательность довольно длинная и только еще больше запутает вас, поэтому она будет опущена.

> /Users/junaid/Desktop/calc.py(1)()
-> operators = [ '+', '-', '*', '/' ]
(Pdb) step
> /Users/junaid/Desktop/calc.py(2)()
-> numbers = [ 10, 20 ]
.
.
.
.
> /Users/junaid/Desktop/calc.py(6)calculator()
-> print("Operators available: " )
(Pdb) step
Operators available:
> /Users/junaid/Desktop/calc.py(8)calculator()
-> for op in operators:
(Pdb) step
> /Users/junaid/Desktop/calc.py(10)calculator()
-> print(op)
(Pdb) step
+
> /Users/junaid/Desktop/calc.py(8)calculator()
-> for op in operators:
(Pdb) step
> /Users/junaid/Desktop/calc.py(10)calculator()
-> print(op)

.
.
.
.

Теперь снова запустите всю программу, но на этот раз используйте команду “next” вместо “step”. Я также показал входную и выходную трассировку для этого.

> /Users/junaid/Desktop/calc.py(3)()
-> operators = ['+', '-', '*', '/']
(Pdb) next
> /Users/junaid/Desktop/calc.py(4)()
-> numbers = [10, 20]
(Pdb) next
> /Users/junaid/Desktop/calc.py(6)()
-> def calculator():
(Pdb) next
> /Users/junaid/Desktop/calc.py(15)()
-> def main():
(Pdb) next
> /Users/junaid/Desktop/calc.py(18)()
-> main()
(Pdb) next
Operators available:
+
-
*
/
Numbers to be used:
10
20
--Return--

Хорошо, теперь, когда у нас есть выходная трассировка для обеих этих функций, давайте посмотрим, чем они отличаются. Для функции step вы можете видеть, что при вызове функции calculator она перемещается внутри этой функции и повторяет ее “шагами”, показывая нам точно, что происходит на каждом шаге.

Однако если вы видите выходную трассировку для функции next , то при вызове функции “main” она не показывает нам, что происходит внутри этой функции (то есть последующий вызов функции калькулятора), а затем непосредственно выводит конечный результат за один шаг.

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

Вывод

В этом уроке мы познакомились со сложной техникой отладки приложений python с помощью встроенного модуля PDB. Мы погрузились в различные команды устранения неполадок, которые предоставляет нам PDB, включая операторы next и step , точки останова и т. Д. Мы также применили их к базовой программе, чтобы увидеть их в действии.