如何让Python装饰器在被装饰函数完成后运行?

43 投票
2 回答
26025 浏览
提问于 2025-04-17 14:47

我想用一个装饰器来处理各种函数的审计(主要是Django的视图函数,但不限于此)。为了做到这一点,我希望能够在函数执行后进行审计,也就是说,函数正常运行,如果没有抛出异常返回结果,那么这个装饰器就会记录这个事实。

大概是这样的:

@audit_action(action='did something')
def do_something(*args, **kwargs):
    if args[0] == 'foo':
        return 'bar'
    else:
        return 'baz'

这里的audit_action只会在函数执行完毕后运行。

2 个回答

10

你的装饰器可以在这里自己处理这个问题,比如说:

def audit_action(function_to_decorate):
    def wrapper(*args, **kw):
        # Calling your function
        output = function_to_decorate(*args, **kw)
        # Below this line you can do post processing
        print "In Post Processing...."
        return output
    return wrapper
66

装饰器通常会返回一个包装函数;你只需要在调用被装饰的函数后,把你的逻辑放在这个包装函数里。

def audit_action(action):
    def decorator_func(func):
        def wrapper_func(*args, **kwargs):
            # Invoke the wrapped function first
            retval = func(*args, **kwargs)
            # Now do something here with retval and/or action
            print('In wrapper_func, handling action {!r} after wrapped function returned {!r}'.format(action, retval))
            return retval
        return wrapper_func
    return decorator_func

所以 audit_action(action='did something') 是一个装饰器工厂,它返回一个特定范围内的 decorator_func,这个函数用来装饰你的 do_something 函数(也就是 do_something = decorator_func(do_something))。

在装饰之后,你的 do_something 这个引用就被替换成了 wrapper_func。调用 wrapper_func() 会导致原来的 do_something() 被执行,然后 你在包装函数里的代码 可以进行其他操作。

上面的代码,加上你的示例函数,会产生以下输出:

>>> do_something('foo')
In wrapper_func, handling action 'did something' after wrapped function returned 'bar'
'bar'

撰写回答