Пошаговое выполнение Python кода: отладка от А до Я

Раздел: Разработка на Python -> Отладка

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

Основные способы пошаговой отладки

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

Модуль pdb (Python Debugger) предоставляет интерактивную среду для пошагового выполнения. Основные команды: n (next), s (step into), c (continue), l (list), p (print), q (quit). Точка останова устанавливается вызовом pdb.set_trace().


# factorial.py
import pdb

def factorial(n):
    if n == 1:
        return 1
    else:
        result = n * factorial(n-1)
        return result

pdb.set_trace()
print(factorial(5))

Most recent call last python (ошибка 'most recent call last' в python)

После запуска выполнение останавливается на строке pdb.set_trace(). Далее можно использовать команды:


(Pdb) n   # выполнить следующую строку
(Pdb) s   # войти в вызов функции factorial
(Pdb) l   # показать текущий участок кода
(Pdb) p n # вывести значение переменной n
(Pdb) c   # продолжить выполнение до следующей точки останова

Python cannot import name (ошибка импорта: cannot import name)

Такая отладка подходит для любого скрипта, не требует IDE и работает в консоли.

Типичные проблемы: забыть удалить pdb.set_trace() из продакшен-кода; отсутствие возможности перемещаться по стеку вызовов; необходимость ручного ввода команд.

Как использовать print-отладку для быстрой проверки?

Простая вставка вывода значений переменных с помощью print() это самый доступный метод. Пример:


def find_max(arr):
    max_val = arr[0]
    for x in arr:
        print(f'Текущий элемент: {x}, максимум: {max_val}')
        if x > max_val:
            max_val = x
    return max_val

Traceback python module (трассировка ошибок python)

Вывод:

Текущий элемент: 3, максимум: 3
Текущий элемент: 5, максимум: 3
Текущий элемент: 2, максимум: 5

команда python не найдена (ошибка 'команда python не найдена')

Этот способ не требует дополнительных инструментов, но после отладки все print нужно удалить, иначе вывод будет засорён.

Типичные ошибки: оставленные print в финальном коде; смешивание отладочного вывода с основным; отсутствие контекста (непонятно, откуда вывод).

Как организовать логирование для отладки?

Модуль logging позволяет гибко настраивать вывод отладочной информации. Уровни: DEBUG, INFO, WARNING, ERROR, CRITICAL.


import logging

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[logging.StreamHandler()]
)

def divide(a, b):
    logging.debug('Деление %s на %s', a, b)
    if b == 0:
        logging.error('Попытка деления на ноль')
        return None
    return a / b

result = divide(10, 0)

File python input 2 line 1 (ошибка при вводе/выводе файла (синтаксис input) в python)

Вывод:

2025-04-09 12:00:00,000 - root - DEBUG - Деление 10 на 0
2025-04-09 12:00:00,000 - root - ERROR - Попытка деления на ноль

Python вывести ошибку (вывод ошибки в python)

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

Проблемы: необходимо правильно настроить уровень логирования; избыточный вывод может замедлить выполнение; забыть добавить logging.getLogger(__name__) для модулей.

Как использовать функцию breakpoint() в Python 3.7+?

Функция breakpoint() это современная альтернатива pdb.set_trace(). Она вызывает отладчик по умолчанию (обычно pdb). При этом можно перенаправить вызов на любой отладчик через переменную окружения PYTHONBREAKPOINT.


def process(data):
    breakpoint()  # точка останова
    for item in data:
        # логика
        pass

Python не выводит ничего (почему python не выводит ничего)

Запуск:

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

найти ошибки в коде python (поиск ошибок в коде python)

Если отладчик не нужен, можно задать PYTHONBREAKPOINT=0, и breakpoint() будет проигнорирован.

Проблемы: в некоторых средах (например, Sublime Text) может не быть встроенного отладчика; при использовании IDE лучше ставить точки через интерфейс.

Как отлаживать в PyCharm или других IDE?

Современные IDE предоставляют графический интерфейс для отладки. В PyCharm можно установить точку останова (красный кружок), затем запустить скрипт в режиме отладки. Кнопки: Step Over (F8), Step Into (F7), Resume (F9). В окне Variables отображаются текущие значения переменных. Пример:


def calc_sum(limit):
    total = 0
    for i in range(limit):
        total += i
    return total

calc_sum(10)

Точку можно установить на строке total += i и пошагово проследить, как меняется total.

Ошибки: запуск без отладчика (кнопка Run вместо Debug); пропуск исключений при отсутствии точек остановки на исключения.

Расширенные примеры отладки

Отладка рекурсивной функции с трассировкой стека

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

Пример

def fib(n, depth=0):
    indent = '  ' * depth
    print(f'{indent}fib({n}) called')
    if n <= 1:
        return n
    result = fib(n-1, depth+1) + fib(n-2, depth+1)
    print(f'{indent}fib({n}) = {result}')
    return result

fib(4)
fib(4) called
  fib(3) called
    fib(2) called
      fib(1) called
      fib(0) called
    fib(1) called
  fib(2) called
    fib(1) called
    fib(0) called
fib(4) = 3

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

Проблема: большой объем вывода при глубокой рекурсии; замедление выполнения.

Использование ipdb для цветной отладки

Модуль ipdb предоставляет интерфейс с подсветкой синтаксиса, автодополнением и историей команд. Установка: pip install ipdb. Замена pdb на ipdb не требует изменения логики.

Пример

import ipdb

def process(items):
    ipdb.set_trace()
    for item in items:
        # ...
        pass

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

Проблемы: требуется установка; в некоторых консолях цвета могут не отображаться.

Условная точка останова в pdb

Иногда нужно остановиться только при определённом условии. pdb позволяет задать условие через команду condition.

Пример

import pdb

def find_duplicates(data):
    seen = {}
    for idx, val in enumerate(data):
        if val in seen:
            pdb.set_trace()  # остановка при первом дубликате
        seen[val] = idx
    return seen

data = [1,2,3,2,5]
find_duplicates(data)

Можно также использовать break lineno, condition:

Пример

import pdb; pdb.set_trace()
# в отладчике:
(Pdb) break 5, val == 2
(Pdb) c

Точка останова сработает только когда val == 2.

Ошибки: неправильное указание номера строки; забыть удалить точку после отладки.

Постмортем-отладка с pdb.pm()

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

Пример

import pdb

def divide(a, b):
    return a / b

try:
    result = divide(10, 0)
except:
    pdb.pm()  # входим в отладчик в точке исключения

В отладчике можно выполнить:

(Pdb) list  # показывает код вокруг ошибки
(Pdb) up    # перемещение по стеку
(Pdb) print(a, b)
(Pdb) q

Метод полезен, когда исключение не удаётся воспроизвести в пошаговом режиме.

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

Код Python по шагам - comments

En
Python код по шагам (python)