Передавайте классы исключений, а не экземпляры. При ошибке найдите первое подходящее соответствие через isinstance, вызовите callback, остальные исключения пробросьте.
Декоратор для обработки исключений с вызовом колбэков
Передавайте классы исключений, а не экземпляры. При ошибке найдите первое подходящее соответствие через isinstance, вызовите callback, остальные исключения пробросьте.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо реализовать декоратор, который в качестве параметра принимает список кортежей — соответствие исключения и функции‑обработчика. При возникновении указанного исключения в теле оборачиваемой функции декоратор должен вызвать привязанный к нему колбэк.
def handler(pairs: list[tuple[Exception, Callable[[], None]]]):
...
Ответ
Передавайте классы исключений, а не экземпляры. При ошибке найдите первое подходящее соответствие через isinstance, вызовите callback, остальные исключения пробросьте.
from functools import wraps
from typing import Callable
def handler(pairs: list[tuple[type[Exception], Callable[[], None]]]):
rules = tuple(pairs)
def decorate(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as error:
for error_type, callback in rules:
if isinstance(error, error_type):
callback()
return None
raise
return wrapper
return decorate
Здесь обработанное исключение подавляется, результатом становится None; это выбранный контракт. Если нужен проброс после callback, замените return None на raise. Порядок правил важен для наследуемых исключений. Ошибка самого callback не перехватывается повторно этой же цепочкой. Асинхронным функциям нужна отдельная обёртка с await.