обертывание метода класса в try/кроме использования декоратора

У меня есть функция общего назначения, которая отправляет информацию об исключениях в журнал приложений. Я использую функцию exception_handler из методов в классах. Обработчик журнала приложения, который передается и вызывается exception_handler, создает строку JSON, которая фактически отправляется в файл журнала. Это все работает нормально.

def exception_handler(log, terminate=False):
    exc_type, exc_value, exc_tb = sys.exc_info()
    filename, line_num, func_name, text = traceback.extract_tb(exc_tb)[-1]
    log.error('{0} Thrown from module: {1} in {2} at line: {3} ({4})'.format(exc_value, filename, func_name, line_num, text))
    del (filename, line_num, func_name, text)
    if terminate:
        sys.exit()

Я использую его следующим образом: (гиперупрощенный пример)

from utils import exception_handler

class Demo1(object):
    def __init__(self):
        self.log = {a class that implements the application log}

    def demo(self, name):
        try:
            print(name)
        except Exception:
            exception_handler(self.log, True)

Я хотел бы изменить exception_handler для использования в качестве декоратора для большого количества методов, то есть:

@handle_exceptions
def func1(self, name)
    {some code that gets wrapped in a try / except by the decorator}

Я просмотрел несколько статей о декораторах, но пока не понял, как реализовать то, что я хочу сделать. Мне нужно передать ссылку на активный объект журнала, а также передать 0 или более аргументов в обернутую функцию. Я был бы рад преобразовать exception_handler в метод класса, если это упростит задачу.


person RoyHB    schedule 22.04.2014    source источник


Ответы (2)


Такой декоратор будет просто:

def handle_exceptions(f):
    def wrapper(*args, **kw):
        try:
            return f(*args, **kw)
        except Exception:
            self = args[0]
            exception_handler(self.log, True)
    return wrapper

Этот декоратор просто вызывает обернутую функцию внутри набора try.

Это может применяться только к методам, так как предполагается, что первый аргумент равен self.

person Martijn Pieters    schedule 22.04.2014
comment
Спасибо Мартин. Это выглядит хорошо, но как передать self.log в handle_exceptions? В нем нет видимого «я». - person RoyHB; 22.04.2014
comment
@RoyHB: Ах, я пропустил, что вы использовали self.log, приношу свои извинения. Скорректировано для использования args[0], но вы также можете заставить wrapper() принимать явный аргумент self с def wrapper(self, *args, **kw) и использовать return f(self, *args, **kw). - person Martijn Pieters; 22.04.2014
comment
Разве внизу не должно быть return wrapper? - person Ethan Bierlein; 11.06.2015
comment
@EthanBierlein: действительно должно быть. - person Martijn Pieters; 11.06.2015

Спасибо Martijn за то, что указал мне правильное направление. Я не смог заставить его предложенное решение работать, но после небольшого поиска на основе его примера следующее работает нормально:

def handle_exceptions(fn):
    from functools import wraps
    @wraps(fn)
    def wrapper(self, *args, **kw):
        try:
            return fn(self, *args, **kw)
        except Exception:
            exception_handler(self.log)
    return wrapper
person RoyHB    schedule 22.04.2014