Traceback в Python: как читать и анализировать сообщения об ошибках

Раздел: Python -> Отладка

Использование модуля traceback для отладки

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

Модуль traceback предоставляет функции для работы с трассировкой стека. Основной способ фиксации ошибки с сохранением контекста - использование traceback.format_exc() или traceback.print_exc() внутри блока except.

import traceback

try:
    result = 1 / 0
except ZeroDivisionError:
    error_message = traceback.format_exc()
    print(error_message)

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

В переменной error_message сохраняется полный текст с указанием файла, строки, вызова и самого исключения. Это удобно для логирования.

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

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

Типичная ошибка:

Использование traceback.print_exc() без аргументов выводит трейс в stderr, что может быть неудобно при интеграции с логами. Рекомендуется использовать format_exc() для получения строки и последующей записи в нужный поток.

Как разобрать стек на отдельные фреймы, а не просто вывести текст?

Используйте traceback.extract_tb() из объекта трейсбэка, который можно получить через sys.exc_info().

import sys, traceback

try:
    raise ValueError("пример")
except:
    exc_type, exc_value, exc_tb = sys.exc_info()
    frames = traceback.extract_tb(exc_tb)
    for frame in frames:
        print(frame.filename, frame.lineno, frame.name, frame.line)

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

<stdin> 3 <module> raise ValueError("пример")

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

Проблема:

Объект exc_tb после блока except может быть перезаписан. Лучше сразу сохранить ссылки на exc_type, exc_value, exc_tb.

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

Функция traceback.format_exception() позволяет контролировать количество фреймов через параметр limit.

try:
    import nonexistent_module
except ImportError:
    tb_str = ''.join(traceback.format_exception(*sys.exc_info(), limit=2))
    print(tb_str)

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

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

Как напечатать текущий стек без исключения (для отладки)?

Используйте traceback.print_stack() или traceback.format_stack(). Это полезно для понимания, откуда была вызвана функция.

def inner():
    traceback.print_stack()

def outer():
    inner()

outer()

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

  File "<stdin>", line 7, in <module>
  File "<stdin>", line 5, in outer
  File "<stdin>", line 2, in inner

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

Как добавить пользовательскую информацию в трейсбэк?

Можно перехватить исключение и дополнить сообщение, например, значением переменных.

def safe_divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as e:
        raise RuntimeError(f"Нельзя делить {a} на {b}") from e

try:
    safe_divide(10, 0)
except RuntimeError:
    traceback.print_exc()

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

Traceback (most recent call last):
  File "<stdin>", line 3, in safe_divide
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 8, in <module>
RuntimeError: Нельзя делить 10 на 0

Цепочка исключений (raise ... from) сохраняет причину, что упрощает отладку.

Ошибка:

При использовании raise ... from None цепочка обрывается, и информация о первом исключении теряется. Используйте это только когда явно нужно скрыть внутреннюю ошибку.

Расширенные примеры работы с traceback

Пример
# Пример: форматирование с указанием имени файла и номера строки
import traceback, sys

def parse_data(data):
    try:
        value = int(data)
        return value
    except ValueError as exc:
        exc_type, exc_value, exc_tb = sys.exc_info()
        # Получаем только последние 3 фрейма
        formatted = traceback.format_exception(exc_type, exc_value, exc_tb, limit=3)
        print(''.join(formatted))

parse_data('не число')
Traceback (most recent call last):
  File "<stdin>", line 3, in parse_data
ValueError: invalid literal for int() with base 10: 'не число'
Пример
# Пример: использование extract_stack для просмотра точек вызова
import traceback

def a():
    b()

def b():
    c()

def c():
    stack = traceback.extract_stack()
    for frame in stack:
        print(f'{frame.filename}:{frame.lineno} {frame.name} -> {frame.line}')

a()
<stdin>:14 <module> -> a()
<stdin>:3 a -> b()
<stdin>:6 b -> c()
<stdin>:10 c -> print(...)
Пример
# Пример: создание собственного обработчика исключений, запись в файл
import traceback

try:
    x = 1/0
except:
    with open('error.log', 'a') as f:
        traceback.print_exc(file=f)
    print("Ошибка записана в лог", file=sys.stderr)
(в файле error.log появится полный трейсбэк)
Пример
# Пример: извлечение фреймов из объекта traceback и анализ
import sys, traceback

def dangerous():
    return 1/0

try:
    dangerous()
except:
    _, _, tb = sys.exc_info()
    while tb:
        print(f'Frame: {tb.tb_frame.f_code.co_name} at line {tb.tb_lineno}')
        tb = tb.tb_next
Frame: dangerous at line 2
Frame: <module> at line 7
Пример
# Пример: использование format_exception_only для получения только сообщения об ошибке
import traceback

try:
    raise KeyError('отсутствует ключ')
except KeyError:
    msg = traceback.format_exception_only(type(KeyError), KeyError('отсутствует ключ'))
    print(''.join(msg))
KeyError: 'отсутствует ключ'
Пример
# Пример: кастомный класс исключения с полным трейсбэком в атрибуте
import traceback

class DetailedException(Exception):
    def __init__(self, message, exc_info=None):
        super().__init__(message)
        if exc_info:
            self.traceback_str = ''.join(traceback.format_exception(*exc_info))
        else:
            self.traceback_str = traceback.format_exc()

try:
    with open('missing.txt') as f:
        pass
except FileNotFoundError as e:
    raise DetailedException('Файл не найден', sys.exc_info())
(Исключение будет содержать строку traceback_str с полным стеком)

Трассировка ошибок Python - comments

En
Traceback python module (python)