Как объявляется декоратор?
Комментарии (3)
Ответ сгенерирован нейросетью и может содержать ошибки
Объявление декоратора в Python
Декоратор в Python — это функция высшего порядка, которая принимает другую функцию в качестве аргумента, добавляет к ней новую функциональность и возвращает модифицированную функцию. Объявление декоратора можно рассмотреть с нескольких уровней: от простого синтаксиса до продвинутых вариантов.
Базовый синтаксис декоратора
На самом простом уровне декоратор — это функция, которая оборачивает другую функцию. Вот классический пример:
def my_decorator(func):
def wrapper():
print("Что-то происходит перед вызовом функции.")
func()
print("Что-то происходит после вызова функции.")
return wrapper
@my_decorator
def say_hello():
print("Привет!")
say_hello()
# Вывод:
# Что-то происходит перед вызовом функции.
# Привет!
# Что-то происходит после вызова функции.
Ключевые элементы объявления:
- Функция-декоратор (
my_decorator) — принимает целевую функцию как аргумент. - Внутренняя функция-обёртка (
wrapper) — содержит дополнительную логику и вызывает оригинальную функцию. - Возврат обёртки — декоратор возвращает функцию
wrapper, заменяя собой оригинальную. - Синтаксис
@— применяется непосредственно над определением функции.
Декораторы с аргументами
Бывают ситуации, когда сам декоратор должен принимать параметры. В этом случае создаётся дополнительный уровень вложенности:
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Привет, {name}!")
greet("Анна")
# Выведет "Привет, Анна!" три раза
Сохранение метаданных функции
Важная проблема декораторов — сохранение метаданных оригинальной функции (имя, документация). Для этого используется декоратор functools.wraps:
import functools
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
import time
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
def calculate_sum(n):
"""Возвращает сумму чисел от 1 до n."""
return sum(range(1, n + 1))
print(calculate_sum.__name__) # Выведет "calculate_sum", а не "wrapper"
print(calculate_sum.__doc__) # Выведет документацию оригинальной функции
Классы как декораторы
Декораторы можно реализовывать не только функциями, но и классами. Для этого класс должен реализовывать метод __call__:
class CountCalls:
def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Вызов #{self.num_calls} функции {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Привет!")
say_hello() # Выведет: "Вызов #1 функции say_hello" и "Привет!"
say_hello() # Выведет: "Вызов #2 функции say_hello" и "Привет!"
Несколько декораторов для одной функции
Функцию можно декорировать несколькими декораторами. Они применяются снизу вверх:
def decorator1(func):
def wrapper():
print("Декоратор 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Декоратор 2")
func()
return wrapper
@decorator1
@decorator2
def my_function():
print("Оригинальная функция")
my_function()
# Вывод:
# Декоратор 1
# Декоратор 2
# Оригинальная функция
Практическое применение в QA Automation
В автоматизации тестирования декораторы особенно полезны для:
- Логирования вызовов методов и функций
- Измерения времени выполнения тестов
- Повторных попыток при неудачных тестах (retry mechanism)
- Проверки предусловий перед выполнением теста
- Авторизации и управления сессиями
def retry(max_attempts=3, delay=1):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
print(f"Попытка {attempt + 1} не удалась: {e}. Повтор через {delay} сек.")
time.sleep(delay)
return None
return wrapper
return decorator
@retry(max_attempts=3, delay=2)
def unstable_api_call():
# Может иногда падать
response = requests.get("https://api.example.com/data")
response.raise_for_status()
return response.json()
Таким образом, объявление декоратора в Python — это гибкий механизм, позволяющий расширять поведение функций без изменения их исходного кода. Понимание различных способов объявления декораторов критически важно для создания поддерживаемого и расширяемого кода в автоматизации тестирования.