"аутсорсинг" обработка исключений декоратору

многие try/except / finally-предложения не только "уродуют" мой код, но я часто использую идентичную обработку исключений для аналогичных задач. Поэтому я рассматривал возможность сокращения избыточности путем "аутсорсинга" их на a ... оформитель.

поскольку я был уверен, что не буду первым, кто придет к такому выводу, я погуглил и нашел это - имхо - гениальным рецепт который добавил возможность обрабатывать более одного исключения.

но я был удивлен, почему это не кажется широко известной и используемой практикой как таковой, поэтому мне было интересно, может быть, есть аспект, который я не рассматривал?

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

  2. может быть, есть даже пакет / модуль, который поддерживает создание такой обработки исключений разумным способом?

3 ответов


самая большая причина сохранить блоки try/except/finally в самом коде заключается в том, что восстановление ошибок обычно является неотъемлемой частью функции.

например, если бы у нас были свои :

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

в принципе, недостатком является то, что вы больше не можете решить, как обрабатывать исключение в контексте вызова (просто позволяя исключению распространяться). В некоторых случаях это может привести к отсутствию разделения ответственности.


  1. декоратор в Python не то же самое, что шаблон декоратора, думал, что есть некоторое сходство. Это не совсем понятно, что вы имеете в виду здесь, но я думаю, что вы имеете в виду тот, от Python (таким образом, лучше не использовать слово pattern)

  2. декораторы из Python не так полезны для обработки исключений, потому что вам нужно будет передать некоторый контекст декоратору. То есть вы либо передадите глобальный контекст, либо скроете определения функций в некотором внешнем контексте, который требует, я бы сказал, шепелявого образа мышления.

  3. вместо декораторов вы можете использовать contextmanagers. И я использую их для этой цели.