You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现可根据被装饰函数执行自定义异常后续操作的装饰器?

实现支持自定义异常处理逻辑的装饰器

你的原装饰器只能统一执行日志记录,要实现针对不同函数执行自定义异常操作(比如回滚),可以通过以下两种实用方案改造:


方案1:带参数的装饰器(推荐)

让装饰器接受一个自定义异常处理函数作为参数,这样在装饰不同函数时,可以传入对应的操作逻辑(比如回滚、资源清理等)。

改造后的装饰器代码

import logging

# 默认异常处理:仅记录日志
def default_error_handler(func, exc):
    logging.error('Error in "{}" function: {}'.format(func.__name__, str(exc)))

def exception_handler(error_handler=default_error_handler):
    def decorator(func):
        def inner_function(*args, **kwargs):
            try:
                output = func(*args, **kwargs)
                return output
            except Exception as exc:
                # 调用传入的自定义处理函数,传递被装饰函数和异常对象
                error_handler(func, exc)
        return inner_function
    return decorator

使用示例

比如给数据库操作函数绑定回滚逻辑,给普通函数保留默认日志:

# 自定义数据库回滚处理
def db_rollback_handler(func, exc):
    logging.error('DB operation failed in "{}": {}'.format(func.__name__, str(exc)))
    # 这里替换为实际的回滚代码,比如:
    # db_connection.rollback()
    print(f"[ACTION] Executing rollback for {func.__name__}")

@exception_handler(error_handler=db_rollback_handler)
def update_user_db(user_id, new_data):
    # 模拟数据库操作抛出异常
    raise ValueError("Invalid user data format")

# 使用默认日志处理的函数
@exception_handler()
def sum_2_numbers(x, y):
    return x + y

# 测试
update_user_db(1, {"name": ""})
sum_2_numbers(3, 'a')

方案2:利用函数属性指定处理逻辑

不需要修改装饰器的调用语法,直接给被装饰函数添加一个自定义属性(比如on_exception),装饰器捕获异常时检查并执行该属性对应的逻辑。

改造后的装饰器代码

import logging

def exception_handler(func):
    def inner_function(*args, **kwargs):
        try:
            output = func(*args, **kwargs)
            return output
        except Exception as exc:
            # 检查函数是否有自定义异常处理属性
            if hasattr(func, 'on_exception') and callable(func.on_exception):
                func.on_exception(func, exc)
            else:
                # 无自定义逻辑时执行默认日志
                logging.error('Error in "{}" function: {}'.format(func.__name__, str(exc)))
    return inner_function

使用示例

@exception_handler
def update_user_db(user_id, new_data):
    raise ValueError("Invalid user data format")

# 给函数绑定自定义回滚逻辑
def db_rollback(func, exc):
    logging.error('Rollback triggered for "{}": {}'.format(func.__name__, str(exc)))
    print(f"[ACTION] Rolling back DB changes for {func.__name__}")

update_user_db.on_exception = db_rollback

@exception_handler
def sum_2_numbers(x, y):
    return x + y

# 测试
update_user_db(1, {})
sum_2_numbers(3, 'a')

方案对比

  • 带参数的装饰器:可读性更强,适合在装饰函数时就明确异常处理逻辑的场景,代码结构更清晰。
  • 函数属性方式:灵活性更高,支持后续动态修改异常处理逻辑,无需改动装饰器语法。

内容的提问来源于stack exchange,提问作者mat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 05:35:20