Как отлаживать 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)\n2025-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
Проблема: трассировка замедляет выполнение и выводит много лишней информации. Решение: использовать условные проверки внутри функции трассировки, например, фильтровать по имени файла или строке.