如何扩展functools.wraps装饰器的功能?

时间:2012-04-05 16:04:05

标签: python decorator functools

我想创建一个新的装饰器代替@wraps(f),它可以执行任何魔法@wraps(f)以及其他任何操作。我该怎么做?

具体来说,我有几个装饰形式:

def decorator(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        # does some stuff in here
        return f(*args, **kwargs)
    if not hasattr(wrapper, '_first_line'):
        wrapper._first_line = inspect.getsourcelines(f)[1]
    return wrapper

似乎我应该能够创建像@wraps_with_first_line(f)这样的装扮器,它将完成@wraps(f)正在做的所有事情以及if not hasattr(wrapper, '_first_line'): wrapper._first_line = inspect.getsourcelines(f)[1]

2 个答案:

答案 0 :(得分:3)

您应该遵循添加指向包装函数的__wrapped__属性的良好做法,而不是添加该包装函数的单个属性。 functools.wraps() wraps()自动执行此操作,但如果您使用的是旧版本的Python而不是3.2,则可以轻松扩展__wrapped__以添加def my_wraps(wrapped, **kwargs): def decorator(wrapper): functools.update_wrapper(wrapper, wrapped, **kwargs) wrapper.__wrapped__ = wrapped return decorator

def orig_function(f):
    try:
        while True:
            f = f.__wrapped__
    except AttributeError:
        return f

编辑:这是一个从可能的多重装饰函数中提取原始函数的函数:

{{1}}

答案 1 :(得分:1)

如果您要添加的内容已经是包装对象的属性,那么您可以使用:

def wraps_with_first_line(f):
    def wrap(wrapper):
        wrapper = wraps(f)(wrapper)
        if not hasattr(wrapper, '_first_line'):
            wrapper._first_line = inspect.getsourcelines(f)[1] 
        return wrapper
    return wrap

如果 已经是包装对象的属性,请使用Sven的方法。