Я был невероятно раздражен этой проблемой и в итоге написал библиотеку для ее решения: decopatch .
Он поддерживает два стиля разработки: вложенный (как в pythonфабрики декораторов) и квартира (на один уровень меньше вложенности).Вот как ваш пример будет реализован в плоском режиме:
from decopatch import function_decorator, DECORATED
from makefun import wraps
@function_decorator
def foo_register(method_name=None, method=DECORATED):
if method_name is None:
method.gw_method = method.__name__
else:
method.gw_method = method_name
# create a signature-preserving wrapper
@wraps(method)
def wrapper(*args, **kwargs):
method(*args, **kwargs)
return wrapper
Обратите внимание, что здесь я использую makefun.wraps вместо functools.wraps
, чтобы подпись полностью сохранялась (оболочкавообще не вызывается, если аргументы недопустимы).
decopatch
поддерживает дополнительный стиль разработки, который я называю double-flat , который предназначен для создания оболочек функций, сохраняющих сигнатурыкак этот.Ваш пример будет реализован следующим образом:
from decopatch import function_decorator, WRAPPED, F_ARGS, F_KWARGS
@function_decorator
def foo_register(method_name=None,
method=WRAPPED, f_args=F_ARGS, f_kwargs=F_KWARGS):
# this is directly the wrapper
if method_name is None:
method.gw_method = method.__name__
else:
method.gw_method = method_name
method(*f_args, **f_kwargs)
Обратите внимание, что в этом стиле весь ваш код выполняется в вызовах method
.Это может быть нежелательно - возможно, вы захотите выполнять вещи только один раз во время оформления - для этого предыдущий стиль будет лучше.
Вы можете проверить, работают ли оба стиля:
@foo_register
def my_function():
print('hi...')
@foo_register('say_hi')
def my_function():
print('hi...')
Пожалуйста, проверьте документацию для деталей.