inspect
. Например:
import inspect
class MyException(Exception):
def __init__(self, message):
frame = inspect.currentframe().f_back
self.filename = frame.f_code.co_filename
self.lineno = frame.f_lineno
self.message = message
super().__init__(f"{message} (file: {self.filename}, line: {self.lineno})")
try:
# some code that might raise an exception
raise MyException("Something went wrong")
except MyException as e:
print(e)
В данном примере, при создании исключения MyException
, извлекается информация о файле и номере строки, где исключение было выброшено, и добавляется к сообщению об ошибке.
Для того, чтобы исключение передавало информацию о вызвавшем его коде (например, строку кода), можно использовать модуль traceback
.
Основная идея заключается в том, чтобы в обработчике исключения (или при создании исключения) получить стек вызовов и извлечь из него необходимую информацию, такую как имя файла, номер строки и контекст.
Вот пример кода, демонстрирующий, как это сделать:
import traceback
import sys
class MyCustomError(Exception):
def __init__(self, message, filename=None, lineno=None, code=None):
super().__init__(message)
self.filename = filename
self.lineno = lineno
self.code = code
def my_function(a, b):
try:
result = a / b
except ZeroDivisionError:
tb = traceback.extract_stack()[-2] # Get info about the caller (my_function)
raise MyCustomError("Деление на ноль!", tb.filename, tb.lineno, tb.line) from None # Suppress chained exception
return result
try:
my_function(10, 0)
except MyCustomError as e:
print(f"Ошибка: {e}")
print(f"Файл: {e.filename}")
print(f"Строка: {e.lineno}")
print(f"Код: {e.code}")
except Exception as e:
print(f"Другая ошибка: {e}")
Разъяснение:
MyCustomError
, который принимает в конструкторе сообщение об ошибке, имя файла, номер строки и строку кода.my_function
, в блоке except
, используется traceback.extract_stack()
для получения стека вызовов.traceback.extract_stack()[-2]
возвращает фрейм стека вызовов, предшествующий текущему (т.е. вызвавшей функции). Мы берем -2, чтобы получить информацию о строке кода в `my_function`, вызвавшей исключение. `-1` вернуло бы информацию о строке, где `raise` было вызвано.filename
(имя файла), lineno
(номер строки) и line
(строка кода).MyCustomError
. Важно использовать `from None` после `raise MyCustomError(...)` для подавления chaining исключений. В противном случае, traceback будет содержать исходное исключение `ZeroDivisionError`, что усложнит отладку.MyCustomError
и вывод информации об ошибке.Альтернативные подходы и улучшения:
sys._getframe()
: Этот менее предпочтительный способ доступа к фреймам стека может быть быстрее, но не является частью публичного API и может измениться. Рекомендуется использовать traceback
.logging
, которые могут автоматически включать информацию о стеке вызовов в логи.Важно помнить: Чрезмерное использование информации о стеке вызовов может снизить производительность, поэтому используйте его только тогда, когда это действительно необходимо для отладки или обработки исключений.