Использование отладчика Python

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

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

Интерактивное взаимодействие с отладчиком Python

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

Читайте также: Официальная документация pdb

Для начала создайте простую программу looping.py с глобальными переменными, функцией, которая создаёт вложенный цикл, и конструкцией if __name__ == ‘__main__’: для вызова функции nested_loop().

num_list = [500, 600, 700] alpha_list = ['x', 'y', 'z'] def nested_loop():
for number in num_list:
print(number)
for letter in alpha_list:
print(letter)
if __name__ == '__main__':
nested_loop()

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

python -m pdb looping.py

Флаг -m импортирует любой модуль Python и запускает его как сценарий. В данном случае нужно импортировать и запустить модуль pdb.

Команда вернёт следующий результат:

> /Users/8host/looping.py(1)<module>()
-> num_list = [500, 600, 700] (Pdb)

Первая строка вывода содержит имя текущего модуля (<module>), путь к каталогу и номер строки (в данном случае это 1, но при наличии комментариев или неисполняемых строк номер будет выше). Вторая строка показывает текущую строку исходного кода, которая была выполнена (pdb предоставляет интерактивную консоль для отладки). Вы можете использовать команду help, чтобы узнать другие команды; чтобы узнать больше о конкретной команде, введите:

help команда

Обратите внимание, что консоль pdb отличается от интерактивной оболочки Python.

Отладчик Python автоматически запустится, когда он достигнет конца проверяемой программы. Чтобы закрыть консоль pdb, введите команду quit или exit. Чтобы явно перезапустить программу, используйте команду run.

Перемещение по программе

При работе с программами в отладчике Python для перемещения по коду используются команды list, step и next. Рассмотрим эти команды подробнее.

Команда list позволяет получить контекст текущей строки. К примеру, в случае с первой строкой программы looping.py, (num_list = [500, 600, 700]) результат будет выглядеть так:

(Pdb) list
1  -> num_list = [500, 600, 700] 2     alpha_list = ['x', 'y', 'z'] 3
4
5     def nested_loop():
6         for number in num_list:
7             print(number)
8             for letter in alpha_list:
9                 print(letter)
10
11     if __name__ == '__main__':
(Pdb)

Текущая строка обозначена символом ->.

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

(Pdb) list 3, 7
3
4
5     def nested_loop():
6         for number in num_list:
7             print(number)
(Pdb)

Аргументы list 3, 7 выведут фрагмент с 3 по 7 строку программы.

Построчное перемещение по программе выполняется с помощью step или next.

(Pdb) step
> /Users/8host/looping.py(2)<module>()
-> alpha_list = ['x', 'y', 'z'] (Pdb)
(Pdb) next
> /Users/8host/looping.py(2)<module>()
-> alpha_list = ['x', 'y', 'z'] (Pdb)

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

К примеру, команда step выполнит итерацию по циклам, когда она дойдет до выполнения функции. Она покажет, что именно делает цикл: сначала она выведет число с помощью print(number), а затем выведет буквы с помощью print(letter).

(Pdb) step
> /Users/8host/looping.py(5)<module>()
-> def nested_loop():
(Pdb) step
> /Users/8host/looping.py(11)<module>()
-> if __name__ == '__main__':
(Pdb) step
> /Users/8host/looping.py(12)<module>()
-> nested_loop()
(Pdb) step
--Call--
> /Users/8host/looping.py(5)nested_loop()
-> def nested_loop():
(Pdb) step
> /Users/8host/looping.py(6)nested_loop()
-> for number in num_list:
(Pdb) step
> /Users/8host/looping.py(7)nested_loop()
-> print(number)
(Pdb) step
500
> /Users/8host/looping.py(8)nested_loop()
-> for letter in alpha_list:
(Pdb) step
> /Users/8host/looping.py(9)nested_loop()
-> print(letter)
(Pdb) step
x
> /Users/8host/looping.py(8)nested_loop()
-> for letter in alpha_list:
(Pdb) step
> /Users/8host/looping.py(9)nested_loop()
-> print(letter)
(Pdb) step
y
> /Users/8host/looping.py(8)nested_loop()
-> for letter in alpha_list:
(Pdb)

Команда next выполнит функцию, не показывая пошагово каждого этапа процесса. Остановите текущую сессию с помощью команды exit и снова запустите отладчик.

python -m pdb looping.py

Запустите команду next:

(Pdb) next
> /Users/8host/looping.py(5)<module>()
-> def nested_loop():
(Pdb) next
> /Users/8host/looping.py(11)<module>()
-> if __name__ == '__main__':
(Pdb) next
> /Users/8host/looping.py(12)<module>()
-> nested_loop()
(Pdb) next
500
x
y
z
600
x
y
z
700
x
y
z
--Return--
> /Users/8host/looping.py(12)<module>()->None
-> nested_loop()
(Pdb)

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

(Pdb) pp num_list
[500, 600, 700] (Pdb)

Большинство команд pdb имеют более короткие псевдонимы. Для команды step это s, а для next – n. Команда help выведет список доступных псевдонимов.

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

Точки останова

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

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

Точки останова можно разместить в строках с определённым номером с помощью синтаксиса <program_file>:<line_number>:

(Pdb) break looping.py:5
Breakpoint 1 at /Users/8host/looping.py:5
(Pdb)

Чтобы удалить все текущие точки останова, введите clear и y.

Также точку останова можно разместить по функции:

(Pdb) break looping.nested_loop
Breakpoint 1 at /Users/8host/looping.py:5
(Pdb)

Чтобы удалить текущую точку, введите clear и y.

Также можно создать условие:

(Pdb) break looping.py:7, number > 500
Breakpoint 1 at /Users/8host/looping.py:7
(Pdb)

Если сейчас запустить команду continue, программа остановится, когда значение number x станет больше 500 (то есть, во время второй итерации цикла).

(Pdb) continue
500
x
y
z
> /Users/8host/looping.py(7)nested_loop()
-> print(number)
(Pdb)

Вывести список точек останова можно с помощью команды break без аргументов.

(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at /Users/8host/looping.py:7
stop only if number > 500
breakpoint already hit 2 times
(Pdb)

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

(Pdb) break looping.py:11
Breakpoint 2 at /Users/8host/looping.py:11
(Pdb) disable 1
Disabled breakpoint 1 at /Users/8host/looping.py:7
(Pdb) break
Num Type         Disp Enb   Where
1   breakpoint   keep no    at /Users/8host/looping.py:7
stop only if number > 500
breakpoint already hit 2 times
2   breakpoint   keep yes   at /Users/8host/looping.py:11
(Pdb)

Включить точку можно с помощью команды enable, а удалить – с помощью clear.

(Pdb) enable 1
Enabled breakpoint 1 at /Users/8host/looping.py:7
(Pdb) clear 2
Deleted breakpoint 2 at /Users/8host/looping.py:11
(Pdb)

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

Интеграция отладчика pdb в программу

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

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

# Import pdb module
import pdb
num_list = [500, 600, 700] alpha_list = ['x', 'y', 'z'] def nested_loop():
for number in num_list:
print(number)
# Trigger debugger at this line
pdb.set_trace()
for letter in alpha_list:
print(letter)
if __name__ == '__main__':
nested_loop()

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

Импорт модуля pdb и функция pdb.set_trace() позволяют запустить программу как обычно.

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

Отладчик Python позволяет изменять поток программы во время выполнения с помощью команды jump. Это позволяет пропустить фрагменты программы, предотвратить запуск какого-либо кода или вернуться назад, чтобы снова запустить код.

Рассмотрим эту функцию на примере небольшой программы, которая создает список букв, содержащихся в строке 8host = “8host”:

def print_8host():
8host_list = [] 8host = "8host"
for letter in 8host:
8host_list.append(letter)
print(8host_list)
if __name__ == "__main__":
print_8host()

Запустите программу:

python letter_list.py
['8'] ['8', 'h'] ['8', 'h', 'o'] ['8', 'h', 'o', 's'] ['8', 'h', 'o', 's', 't']

С помощью отладчика Python можно изменить выполнение программы, пропустив один цикл. Это прервёт цикл for.

Читайте также: Циклы for

python -m pdb letter_list.py
> /Users/8host/letter_list.py(1)<module>()
-> def print_8host():
(Pdb) list
1  -> def print_8host():
2         8host_list = [] 3         8host = "8host"
4         for letter in 8host:
5             8host_list.append(letter)
6             print(8host_list)
7
8     if __name__ == "__main__":
9         print_8host()
10
11
(Pdb) break 5
Breakpoint 1 at /Users/8host/letter_list.py:5
(Pdb) continue
> /Users/8host/letter_list.py(5)print_8host()
-> 8host_list.append(letter)
(Pdb) pp letter
'8'
(Pdb) continue
['8'] > /Users/8host/letter_list.py(5)print_8host()
-> 8host_list.append(letter)
(Pdb) jump 6
> /Users/8host/letter_list.py(6)print_8host()
-> print(8host_list)
(Pdb) pp letter
'h'
(Pdb) disable 1
Disabled breakpoint 1 at /Users/8host/letter_list.py:5
(Pdb) continue
['8'] ['8', 'o'] ['8', 'o', 's'] ['8', 'o', 's', 't']

В этой сессии отладчик прервёт обработку кода на строке 5, а затем возобновит процесс обработки (также он выведет некоторые значения, чтобы вы могли отслеживать действия). Затем команда jump перепрыгнет на строку 6. В этот момент переменная letter имеет значение а, но код, который отвечает за её отображение, пропущен. Затем точка останова отключается с помощью команды continue, потому значение a не включено в вывод.

Закройте сессию и перезапустите отладчик. Попробуйте вернуться к предыдущему фрагменту программы с помощью jump. Например, можно дважды запустить первую итерацию цикла for.

> /Users/8host/letter_list.py(1)<module>()
-> def print_8host():
(Pdb) list
1  -> def print_8host():
2         8host_list = [] 3         8host = "8host"
4         for letter in 8host:
5             8host_list.append(letter)
6             print(8host_list)
7
8     if __name__ == "__main__":
9         print_8host()
10
11
(Pdb) break 6
Breakpoint 1 at /Users/8host/letter_list.py:6
(Pdb) continue
> /Users/8host/letter_list.py(6)print_8host()
-> print(8host_list)
(Pdb) pp letter
'8'
(Pdb) jump 5
> /Users/8host/letter_list.py(5)print_8host()
-> 8host_list.append(letter)
(Pdb) continue
> /Users/8host/letter_list.py(6)print_8host()
-> print(8host_list)
(Pdb) pp letter
'8'
(Pdb) disable 1
Disabled breakpoint 1 at /Users/8host/letter_list.py:6
(Pdb) continue
['8', '8'] ['8', '8', 'h'] ['8', '8', 'h', 'o'] ['8', '8', 'h', 'o', 's'] ['8', '8', 'h', 'o', 's', 't']

В приведённой выше сессии отладки выполнение кода остановилось на строке 6, затем программа вернулась к строке 5 и продолжила обработку. Затем точка останова в строке 6 была отключена, после чего программа продолжила выполнение. Результат показывает два значения ‘8’ в 8host_list.

Некоторые пропуски и изменения потока программы предотвращает сам отладчик (особенно это касается тех фрагментов кода, которые определяют значения в дальнейшем потоке программы). К примеру, вы не сможете пропустить функции, если аргументы не определены, перейти к середине блока try:except или пропустить блок finally.

Общие команды pdb

Здесь вы найдёте таблицу полезных команд pdb, которые часто используются при работе с отладчиком Python.

 Команда

Краткая форма

Действие

args a Выводит список аргументов текущей функции
break b Создает точку останова (с параметрами) при выполнении. программы
continue c, cont Продолжает выполнение программы.
help h Предоставляет список команд или справку для указанной команды.
jump j Определяет строку, которая будет выполнена далее.
list l Выводит исходный код вокруг текущей строки.
next n Продолжает выполнение до тех пор, пока не будет достигнута или возвращена следующая строка в текущей функции.
step s Выполняет текущую строку.
pp pp Выдаёт структурированные значения выражения.
quit, exit q Прерывает программу.
return r Продолжает выполнение, пока не вернётся текущая функция.

Больше информации можно найти в документации отладчика Python.

Заключение

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

Tags:

Добавить комментарий