2

我想创建一个新的装饰器来代替@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].

4

2 回答 2

3

您应该遵循添加__wrapped__指向包装函数的属性的良好做法,而不是添加该包装函数的单个属性。 新版本functools.wraps()自动执行此操作,但如果您使用的是比 3.2 更旧的 Python 版本,您也可以轻松扩展wraps()以添加__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
于 2012-04-05T16:08:26.930 回答
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 的方法。

于 2012-04-05T16:12:31.233 回答