Вопрос проверяет понимание принципов работы и применения декораторов в Python, что важно для написания чистого, модульного и переиспользуемого кода.
Декоратор в Python — это мощный инструмент, который позволяет модифицировать поведение функции или метода, оборачивая её в другую функцию. По сути, декоратор — это функция высшего порядка, принимающая функцию в качестве аргумента и возвращающая новую, модифицированную функцию. Это реализация паттерна проектирования "Декоратор", адаптированная под синтаксис Python.
Без использования специального синтаксиса декоратор применяется путём явного вызова: my_func = decorator(my_func). Однако Python предоставляет более элегантный и читаемый способ — использовать символ @ прямо над определением функции.
Декораторы находят применение в самых разных сценариях:
Рассмотрим простой декоратор для замера времени выполнения функции:
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs) # Вызов исходной функции
end_time = time.time()
print(f"Функция {func.__name__} выполнилась за {end_time - start_time:.4f} секунд")
return result
return wrapper
# Применение декоратора
@timer_decorator
def calculate_sum(n):
"""Вычисляет сумму чисел от 1 до n."""
total = 0
for i in range(1, n+1):
total += i
return total
# Вызов функции
print(calculate_sum(1000000)) # Будет выведено время выполненияВ этом примере timer_decorator — это функция, которая создаёт и возвращает внутреннюю функцию wrapper. wrapper замеряет время, вызывает исходную функцию func и выводит результат замера. Синтаксис @timer_decorator над calculate_sum автоматически применяет этот декоратор.
Для создания более гибких декораторов, которые сами могут принимать параметры, требуется дополнительный уровень вложенности функций. Например, декоратор, повторяющий выполнение функции заданное количество раз.
def repeat(times):
"""Декоратор, повторяющий вызов функции заданное количество раз."""
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result # Возвращаем результат последнего вызова
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"Привет, {name}!")
greet("Анна") # Сообщение будет выведено три разаВывод: Декораторы стоит применять, когда необходимо добавить сквозную функциональность (cross-cutting concern) к нескольким функциям, не копируя один и тот же код. Они идеально подходят для задач логирования, кеширования, контроля доступа и валидации, делая код более чистым, декларативным и соответствующим принципу DRY (Don't Repeat Yourself).