"аутсорсинг" обработки исключений для декоратора
Многие try/except/finally-clauses не только "угадают" мой код, но я часто нахожусь с использованием одинаковой обработки исключений для подобных задач. Поэтому я рассматривал возможность сокращения избыточности путем "аутсорсинга" их на... декоратора.
Поскольку я был уверен, что не буду первым, чтобы прийти к такому выводу, я нашел googled и нашел это - imho - изобретательный recipe что добавило возможность обработки более чем одного исключения.
Но я был удивлен, почему это, похоже, не является широко известной и используемой практикой как таковой, поэтому мне было интересно, есть ли какой-то аспект, который я не рассматривал?
-
Является ли фальшивым использовать шаблон декоратора для обработки исключений или я просто пропустил его все время? Пожалуйста, просветите меня! Каковы подводные камни?
-
Возможно, существует даже пакет/модуль, который поддерживает создание такой обработки исключений разумным образом?
Ответы
Ответ 1
Самая большая причина для хранения блоков try/except/finally в самом коде состоит в том, что восстановление ошибок обычно является неотъемлемой частью функции.
Например, если у нас есть наша функция int()
:
def MyInt(text):
return int(text)
Что делать, если text
невозможно преобразовать? Вернуть 0
? Вернуть None
?
Если у вас много простых случаев, я вижу, что простой декоратор полезен, но я думаю, что рецепт, который вы связали, пытается сделать слишком много: он позволяет активировать другую функцию для каждого возможного исключения - в таких случаях как те (несколько разных исключений, несколько разных кодов), я бы рекомендовал выделенную функцию обертки.
Здесь мой подход к простому декоратору:
class ConvertExceptions(object):
func = None
def __init__(self, exceptions, replacement=None):
self.exceptions = exceptions
self.replacement = replacement
def __call__(self, *args, **kwargs):
if self.func is None:
self.func = args[0]
return self
try:
return self.func(*args, **kwargs)
except self.exceptions:
return self.replacement
и использование образца:
@ConvertExceptions(ValueError, 0)
def my_int(value):
return int(value)
print my_int('34') # prints 34
print my_int('one') # prints 0
Ответ 2
В принципе, недостатком является то, что вы больше не решаетесь, как обрабатывать исключение в вызывающем контексте (просто разрешая распространение исключения). В некоторых случаях это может привести к отсутствию разделения ответственности.
Ответ 3
-
Декоратор в Python - это не то же самое, что и шаблон Decorator, если есть некоторое сходство. Не совсем понятно, что вы имеете в виду здесь, но я думаю, что вы имеете в виду один из Python (таким образом, лучше не использовать шаблон слова)
-
Декораторы из Python не так полезны для обработки исключений, потому что вам нужно будет передать некоторый контекст декоратору. То есть вы либо проходите глобальный контекст, либо скрываете определения функций в каком-то внешнем контексте, что требует, я бы сказал, LISP -подобного способа мышления.
-
Вместо декораторов вы можете использовать контекстных менеджеров. И я использую их для этой цели.