Я был невероятно раздражен этим и в итоге написал библиотеку для решения этой проблемы: decopatch .
Он поддерживает два стиля разработки: вложенный (как на фабриках Python Decorator) и плоский (на один уровень вложенности меньше). Вот как ваш пример будет реализован в плоском режиме:
from decopatch import function_decorator, DECORATED
from makefun import wraps
@function_decorator
def logged(disabled=False, logger=logging.getLogger('default'), func=DECORATED):
# (1) create a signature-preserving wrapper
@wraps(func)
def _func_wrapper(*f_args, **f_kwargs):
# stuff
result = func(*f_args, **f_kwargs)
# stuff
return result
# (2) return it
return _func_wrapper
Обратите внимание, что я использую makefun.wraps вместо functools.wraps
, чтобы подпись полностью сохранялась (оболочка вообще не вызывается, если аргументы неверны).
decopatch
поддерживает дополнительный стиль разработки, который я называю double-flat , который предназначен для создания оболочек с функцией сохранения подписи, подобных этой. Ваш пример будет реализован так:
from decopatch import function_decorator, WRAPPED, F_ARGS, F_KWARGS
@function_decorator
def logged(disabled=False, logger=logging.getLogger('default'),
func=WRAPPED, f_args=F_ARGS, f_kwargs=F_KWARGS):
# this is directly the signature-preserving wrapper
# stuff
result = func(*f_args, **f_kwargs)
# stuff
return result
Вы можете проверить, что оба стиля работают должным образом:
@logged(disabled=True)
def foo():
pass
@logged
def bar():
pass
foo()
bar()
Пожалуйста, проверьте документацию для деталей.