Расширение функциональности декоратора 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