Расширение функциональности декоратора functools.wraps

Я хотел бы создать новый декоратор для использования вместо @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 ответа

Решение

Если то, что вы хотите добавить, уже не является атрибутом обернутого объекта, то вы можете использовать это:

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

Если это уже атрибут обернутого объекта, используйте метод Свена.

Вы должны скорее следовать хорошей практике добавления __wrapped__ атрибут, указывающий на упакованную функцию, чем добавление отдельных атрибутов этой упакованной функции. Новые версии functools.wraps() сделать это автоматически, но если вы используете более старую версию Python, чем 3.2, вы можете легко расширить 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
Другие вопросы по тегам