使用装饰器在try/except中包装类方法

8 投票
2 回答
7243 浏览
提问于 2025-04-18 03:44

我有一个通用的函数,用来把异常信息发送到应用程序的日志里。我在类的方法中使用了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转换成类中的一个方法,那样可能会更简单。

2 个回答

4

感谢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
16

这个装饰器其实就是这么简单:

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

撰写回答