Сделайте первый аргумент функцией по умолчанию None, а настройки — keyword-only. Внутренняя функция создаёт обёртку с functools.wraps, чтобы introspection видел исходные метаданные и сигнатуру.
Как написать декоратор, который ведет себя одинаково и с аргументами, и без них, не ломая сигнатуру?
Сделайте первый аргумент функцией по умолчанию None, а настройки — keyword-only. Внутренняя функция создаёт обёртку с functools.wraps, чтобы introspection видел исходные метаданные и сигнатуру.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Сделайте первый аргумент функцией по умолчанию None, а настройки — keyword-only. Внутренняя функция создаёт обёртку с functools.wraps, чтобы introspection видел исходные метаданные и сигнатуру.
from functools import wraps
def trace(func=None, *, label="call"):
def decorate(fn):
@wraps(fn)
def wrapped(*args, **kwargs):
print(label)
return fn(*args, **kwargs)
return wrapped
return decorate if func is None else decorate(func)
Поддерживаются @trace, @trace() и @trace(label="work"). wraps задаёт __wrapped__, но фактическая сигнатура обёртки остаётся *args, **kwargs. Пример предназначен для обычных функций; для наблюдения за выполнением coroutine нужна async-обёртка с await.