Traceback в 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 с полным стеком)