Модуль pdb и отладка программы

Последнее обновление: 17.08.2025

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

Зачем нужен отладчик?

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

  • Засорение кода: приходится вставлять и удалять множество временных вызовов print().

  • Неинтерактивность: нельзя изменять переменные или выполнять код "на лету" во время паузы.

  • Ограниченный контекст: print() показывает значение только в одной точке, в то время как отладчик дает доступ ко всему состоянию программы.

pdb решает эти проблемы, предоставляя интерактивную среду прямо в месте "падения" или остановки вашего кода.

Стоит отметить, что у ряда IDE и текстовых редакторов (PyCharm, VS Code) есть интеграция с отладчиком - они используют возможности pdb под капотом, предоставляя графический интерфейс для отладки.

Запуск pdb

Существует несколько способов активировать отладчик.

Запуск из командной строки

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

python3 -m pdb test.py

При выполнении этой команды pdb запустит скрипт "test.py" и остановится на первой исполняемой строке. Для примера пусть у нас есть файл "test.py" со следующим простеньким кодом:

def sum(a, b):
    result = a + b
    return result

print(sum(5, 6))

После запуска командой "python3 -m pdb test.py" вы увидите приглашение (Pdb), что означает, что вы находитесь в сессии отладчика.

eugene@Eugene:/workspace/python/test$ python3 -m pdb test.py
> /workspace/python/test.py(1)<module>()
-> def sum(a, b):
(Pdb) 

Для выхода из отладчика введем команду "q":

eugene@Eugene:/workspace/python/test$ python3 -m pdb test.py
> /workspace/python/test.py(1)<module>()
-> def sum(a, b):
(Pdb) q 
eugene@Eugene:/workspace/python/test$

Вставка точки останова (breakpoint) в коде

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

В Python 3.7 и новее для вставки точки останова применяется встроенная функция breakpoint(). Это современный и гибкий метод. Например:

def sum(a, b):
    breakpoint() # <--- Программа остановится здесь
    result = a + b
    return result

print(sum(5, 6))

В старых версиях Python (также можно использовать и в текущих версиях Python) нужно явным образом импортировать модуль pdb и вызвать функцию pdb.set_trace():

import pdb

def sum(a, b):
    pdb.set_trace() # <--- Программа остановится здесь
    result = a + b
    return result

print(sum(5, 6))

Вне зависимости от того, какой способ применяется - breakpoint() или вызов pdb.set_trace(), когда интерпретатор дойдет до строки с вызовом данных функций, он остановится, и вы также получите доступ к интерактивной консоли pdb:

eugene@Eugene:/workspace/python/test$ python3 test.py
> /workspace/python/test/test.py(3)sum()
-> result = a + b
(Pdb) q

Для выхода из отладчика и программы также можно ввести команду "q".

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

Итак, мы можем запускать скрипт Python в отладчике. Но как управлять отладчиком? Для этого рассмотрим его основные команды:

  • n (next): выполняет текущую строку и переходит к следующей в той же функции. Не заходит внутрь вызываемых функций..

  • s (step): выполняет текущую строку и останавливается на первом возможном шаге. Заходит внутрь вызываемых функций.

  • c (continue): продолжает выполнение программы до следующей точки останова или до конца.

  • l (list): показывает исходный код вокруг текущей строки

  • p <expr> (print()): вычисляет и печатает значение выражения. Например: p user_id или p url.

  • pp <expr>: вычисляет и печатает значение выражения с использованием форматирования (pretty print).

  • b <номер строки> (break): устанавливает новую точку останова. Например: b 25 (на строку 25) или b my_function (на функцию my_function)..

  • b <файл>:<строка>: устанавливает новую точку останова в другом файле.

  • cl <номер>: удаляет точку останова.

  • a (args): показывает аргументы текущей функции

  • w (where): показывает стек вызовов (traceback), чтобы понять, как программа пришла в текущую точку.

  • q (quit): завершает сессию отладки и программу

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

Возьмем ранее определенный скрипт "test.py" со следующим кодом:

def sum(a, b):
    result = a + b
    return result

print(sum(5, 6))

И запустим его командой "python3 -m pdb test.py", после чего нам отобразится приглашение (Pdb), что означает, что мы в отладчике

eugene@Eugene:/workspace/python/test$ python3 -m pdb test.py
> /workspace/python/test.py(1)<module>()
-> def sum(a, b):
(Pdb) 

По умолчанию отображается первая строка скрипта (в нашем случае - def sum(a, b)). Для пошагового прохода по коду с заходом в функции введем команду "s" (step):

eugene@Eugene:/workspace/python/test$ python3 -m pdb test.py
> /workspace/python/test.py(1)<module>()
-> def sum(a, b):
(Pdb) s
> /workspace/python/test/test.py(5)()
-> print(sum(5, 6))
(Pdb)

И мы видим, что отладчик перешел к строке 5 (строка print(sum(5, 6)))

Снова введем команду "s" (step):

eugene@Eugene:/workspace/python/test$ python3 -m pdb test.py
> /workspace/python/test.py(1)<module>()
-> def sum(a, b):
(Pdb) s
> /workspace/python/test/test.py(5)()
-> print(sum(5, 6))
(Pdb) s
--Call--
> /media/eugene/WD10EZEX/workspace/python/test/test.py(1)sum()
-> def sum(a, b):
(Pdb)

Мы видим, что отладчик перешел к выполнению функции sum. Последовательно введем пару раз команд "s":

eugene@Eugene:/workspace/python/test$ python3 -m pdb test.py
> /workspace/python/test.py(1)<module>()
-> def sum(a, b):
(Pdb) s
> /workspace/python/test/test.py(5)()
-> print(sum(5, 6))
(Pdb) s
--Call--
> /media/eugene/WD10EZEX/workspace/python/test/test.py(1)sum()
-> def sum(a, b):
(Pdb) s
> /media/eugene/WD10EZEX/workspace/python/test/test.py(2)sum()
-> result = a + b
(Pdb) s
> /media/eugene/WD10EZEX/workspace/python/test/test.py(3)sum()
-> return result

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

(Pdb) result
11
(Pdb)

Мы видим, что результат равен 11.

Введем еще пару раз команду "s" для выполнения оставшегося кода в программе и завершим ее вводом команды "q":

(Pdb) s
--Return--
> /workspace/python/test/test.py(3)sum()->11
-> return result
(Pdb) s
11
--Return--
> /workspace/python/test/test.py(5)<module>()->None
-> print(sum(5, 6))
(Pdb) q

Пример: поиск ошибки

Допустим, у нас есть функция для подсчета суммы элементов списка:

def total(numbers):
    s = 0
    for n in numbers:
        s = s + n
    return s

print(total([1, "2", 3, 4]))

Здесь возникнет ошибка при сложении числа и строки:

eugene@Eugene:/workspace/python/test$ python3 test.py
Traceback (most recent call last):
  File "/workspace/python/test/test.py", line 7, in <module>
    print(total([1, "2", 3, 4]))
          ^^^^^^^^^^^^^^^^^^^^^
  File "/workspace/python/test/test.py", line 4, in total
    s = s + n
        ~~^~~
TypeError: unsupported operand type(s) for +: 'int' and 'str'
eugene@Eugene:/workspace/python/test$ 

Вставим вызов breakpoint(), чтобы исследовать переменные в момент сбоя:

def total(numbers):
    s = 0
    for n in numbers:
        s = s + n
        breakpoint()
    return s

print(total([1, "2", 3, 4]))

С помощью команд "n" пройдем по выполнению функции, пока не выпадет ошибка и затем введем команду "p n":

eugene@Eugene:/workspace/python/test$ python3 test.py
> /workspace/python/test/test.py(3)total()
-> for n in numbers:
(Pdb) n
> /workspace/python/test/test.py(4)total()
-> s = s + n
(Pdb) n
TypeError: unsupported operand type(s) for +: 'int' and 'str'
> /workspace/python/test/test.py(4)total()
-> s = s + n
(Pdb) p n
'2'
(Pdb) 

И здесь мы видим, что на второй итерации значение "n" равно "2", но представляет строку, из-за чего и возникает ошибка.

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850