обвиващ метод на клас в 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
Благодаря Мартин. Това изглежда добре, освен как да направя pass 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

Благодаря на Мартин, че ме насочи в правилната посока. Не можах да накарам предложеното от него решение да работи, но след малко повече търсене въз основа на неговия пример следното работи добре:

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