Как отлаживать Python-скрипты: подробное руководство

Раздел: Разработка на Python -> Инструменты отладки

Инструменты отладки Python

Как пошагово исполнить код и просмотреть значения переменных?

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

def divide(a, b):\n    result = a / b\n    return result\n\nx = 10\ny = 0\nimport pdb; pdb.set_trace()\nz = divide(x, y)\nprint(z)\n

отладка программы python (отладка программы на python)

При запуске скрипта выполнение остановится на строке с set_trace(). В консоли появится приглашение (Pdb). Основные команды:

  • n (next) - выполнить следующую строку в текущей функции.
  • s (step) - войти внутрь вызываемой функции.
  • c (continue) - продолжить выполнение до следующей точки останова.
  • p variable - вывести значение переменной.
  • l (list) - показать текущую позицию в коде.
  • q (quit) - завершить отладку.
> /path/to/script.py(8)<module>()\n-> z = divide(x, y)\n(Pdb) p x\n10\n(Pdb) n\nZeroDivisionError: division by zero\n

Возможные проблемы

Забыть импортировать pdb или вызвать set_trace(). Если скрипт запущен без отладчика, точки останова игнорируются. Решение: использовать breakpoint() в Python 3.7+ или явно вызывать pdb.set_trace() только при необходимости.

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

Как вызывать отладчик без написания import pdb?

Начиная с Python 3.7, встроена функция breakpoint(). Она по умолчанию вызывает pdb.set_trace(), но может быть перенаправлена через переменную окружения PYTHONBREAKPOINT.

def divide(a, b):\n    return a / b\n\nx = 10\ny = 0\nbreakpoint()\nz = divide(x, y)\nprint(z)\n
(Pdb) p x\n10\n(Pdb) n\nZeroDivisionError\n

Возможная проблема

Интегрированные среды разработки (PyCharm, VSCode) могут переопределять поведение breakpoint() для своих отладчиков. Если требуется именно pdb, следует установить PYTHONBREAKPOINT=0 или явно использовать import pdb; pdb.set_trace().

Как отлаживать с визуальными точками останова и графическим интерфейсом?

PyCharm (Community Edition) имеет встроенный отладчик. Достаточно щелкнуть слева от номера строки, чтобы установить точку останова (красный кружок). Затем запустить скрипт в режиме Debug (кнопка с жучком). Используются кнопки Step Over (F8), Step Into (F7), Resume (F9). В панели Variables отображаются текущие переменные.

# Тот же пример, точка останова на строке result = a / b\ndef divide(a, b):\n    result = a / b  # <- точка останова\n    return result\n\nx = 10\ny = 0\nz = divide(x, y)\nprint(z)\n

Возможная проблема

Отладчик не запускается, если не выбран правильный интерпретатор Python в настройках проекта. Решение: проверить File > Settings > Project > Python Interpreter и убедиться, что используется нужная версия.

Как получать информацию о ходе выполнения без остановки программы?

Модуль logging позволяет записывать сообщения с различным уровнем детализации. Настраивается один раз в начале скрипта.

import logging\nlogging.basicConfig(level=logging.DEBUG,\n                    format='%(asctime)s - %(levelname)s - %(message)s')\n\ndef divide(a, b):\n    logging.debug('Деление {} на {}'.format(a, b))\n    try:\n        result = a / b\n    except ZeroDivisionError:\n        logging.error('Деление на ноль')\n        return None\n    else:\n        logging.info('Результат: {}'.format(result))\n        return result\n\nx = 10\ny = 0\ndivide(x, y)\n
2025-04-08 12:00:00,000 - DEBUG - Деление 10 на 0\n2025-04-08 12:00:00,001 - ERROR - Деление на ноль\n

Возможные проблемы

Сообщения не выводятся, если уровень логирования слишком высок (например, установлен WARNING, а используется DEBUG). Решение: указать level=logging.DEBUG.

Также можно забыть добавить обработчик для вывода в файл. Для записи в файл используется logging.FileHandler.

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

1. Отладка многопоточного приложения с pdb

При использовании pdb в многопоточном коде остановка происходит только в потоке, где вызван breakpoint(). Другие потоки продолжают работу. Для более контролируемой отладки можно добавить breakpoint() внутри функции потока и использовать команду where для просмотра стека.

Пример
import threading\nimport time\n\ndef worker(name):\n    for i in range(5):\n        time.sleep(0.1)\n        breakpoint()  # останавливается в каждом потоке\n        print(f'{name}: {i}')\n\nt1 = threading.Thread(target=worker, args=('A',))\nt2 = threading.Thread(target=worker, args=('B',))\nt1.start()\nt2.start()\nt1.join()\nt2.join()\n
(Pdb) where\n  /lib/python3.10/threading.py(973)_bootstrap()\n  /lib/python3.10/threading.py(1016)_bootstrap_inner()\n  ...\n(Pdb) p name\n'A'\n

Проблема: множественные остановки могут сбивать с толку. Решение: использовать отладку на уровне одного потока или применять условные точки останова (например, if name == 'A': breakpoint()).

2. Удаленная отладка с помощью rpdb

Библиотека rpdb (remote pdb) позволяет подключаться к отладчику по сети. Это полезно для отладки приложений в контейнерах или на удаленных серверах.

Пример
# Установка: pip install rpdb\nimport rpdb\ndef divide(a, b):\n    rpdb.set_trace(host='0.0.0.0', port=4444)\n    return a / b\n\nx = 10\ny = 0\nz = divide(x, y)\nprint(z)\n

После запуска скрипта отладчик ожидает TCP-подключения. Подключиться можно через telnet или nc:

$ nc 127.0.0.1 4444\n> /path/to/script.py(4)divide()\n-> return a / b\n(Pdb) p a\n10\n(Pdb) n\nZeroDivisionError\n

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

3. Автоматическая отладка при ошибках в тестах с pytest

Фреймворк pytest поддерживает опцию --pdb, которая при возникновении ошибки в тесте запускает pdb в точке исключения.

Пример
# test_divide.py\ndef test_divide_by_zero():\n    x = 10\n    y = 0\n    result = x / y  # вызовет ZeroDivisionError\n    assert result is None\n
$ pytest --pdb test_divide.py\n...\ntest_divide.py:3: ZeroDivisionError\n> /path/to/test_divide.py(3)test_divide_by_zero()\n-> result = x / y\n(Pdb) p x\n10\n(Pdb) p y\n0\n(Pdb) q\n

Проблема: --pdb останавливает выполнение всех последующих тестов. Решение: использовать --pdb --pdbcls=... для кастомизации или комбинировать с -x (exit on first error).

4. Кастомный трассировщик с sys.settrace

Модуль sys позволяет установить свою функцию трассировки, которая будет вызываться при каждом событии выполнения (строка, вызов, возврат). Это дает полный контроль над отладкой.

Пример
import sys\n\ndef trace_calls(frame, event, arg):\n    if event == 'line':\n        filename = frame.f_code.co_filename\n        lineno = frame.f_lineno\n        print(f'{filename}:{lineno} {event}')\n    return trace_calls\n\nsys.settrace(trace_calls)\n\ndef divide(a, b):\n    return a / b\n\nx = 10\ny = 0\nz = divide(x, y)\nprint(z)\n
...\nscript.py:10 line\nscript.py:5 line  # внутри divide\nscript.py:10 line (возврат)\nZeroDivisionError\n

Проблема: трассировка замедляет выполнение и выводит много лишней информации. Решение: использовать условные проверки внутри функции трассировки, например, фильтровать по имени файла или строке.

Отладка программы на Python - comments

En
отладка программы python (python)