Вопрос проверяет понимание передачи аргументов через декораторы в Python, что необходимо для создания гибких оберток функций.
Декоратор в Python — это функция, которая принимает другую функцию и возвращает ее модифицированную версию. Чтобы декоратор мог работать с любыми аргументами, внутренняя функция-обертка должна использовать *args и **kwargs. Это позволяет перехватывать все позиционные и именованные аргументы, переданные декорируемой функции, и передавать их дальше.
Рассмотрим простой декоратор, который логирует вызов функции:
def logger(func):
def wrapper(*args, **kwargs):
print(f"Вызов {func.__name__} с args={args}, kwargs={kwargs}")
return func(*args, **kwargs)
return wrapper
@logger
def greet(name, greeting="Привет"):
print(f"{greeting}, {name}!")
greet("Анна")
greet("Иван", greeting="Здравствуйте")В этом примере декоратор logger перехватывает все аргументы, выводит их в консоль и передает в исходную функцию greet. Без *args и **kwargs декоратор не смог бы обработать произвольное количество аргументов.
Такой подход широко используется для создания декораторов, которые добавляют логирование, проверку прав доступа, кэширование или замер времени выполнения. Например, декоратор для измерения времени работы функции:
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} выполнилась за {end - start:.4f} сек")
return result
return wrapper
@timer
def compute(n):
return sum(range(n))
compute(1000000)Использование *args и **kwargs в декораторах делает их универсальными и применимыми к любым функциям, независимо от их сигнатуры. Это ключевой паттерн для создания переиспользуемых оберток в Python.