← Назад к вопросам

Как объявляется декоратор?

2.0 Middle🔥 173 комментариев
#Python#Фреймворки тестирования

Комментарии (3)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Объявление декоратора в Python

Декоратор в Python — это функция высшего порядка, которая принимает другую функцию в качестве аргумента, добавляет к ней новую функциональность и возвращает модифицированную функцию. Объявление декоратора можно рассмотреть с нескольких уровней: от простого синтаксиса до продвинутых вариантов.

Базовый синтаксис декоратора

На самом простом уровне декоратор — это функция, которая оборачивает другую функцию. Вот классический пример:

def my_decorator(func):
    def wrapper():
        print("Что-то происходит перед вызовом функции.")
        func()
        print("Что-то происходит после вызова функции.")
    return wrapper

@my_decorator
def say_hello():
    print("Привет!")

say_hello()
# Вывод:
# Что-то происходит перед вызовом функции.
# Привет!
# Что-то происходит после вызова функции.

Ключевые элементы объявления:

  1. Функция-декоратор (my_decorator) — принимает целевую функцию как аргумент.
  2. Внутренняя функция-обёртка (wrapper) — содержит дополнительную логику и вызывает оригинальную функцию.
  3. Возврат обёртки — декоратор возвращает функцию wrapper, заменяя собой оригинальную.
  4. Синтаксис @ — применяется непосредственно над определением функции.

Декораторы с аргументами

Бывают ситуации, когда сам декоратор должен принимать параметры. В этом случае создаётся дополнительный уровень вложенности:

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 — это гибкий механизм, позволяющий расширять поведение функций без изменения их исходного кода. Понимание различных способов объявления декораторов критически важно для создания поддерживаемого и расширяемого кода в автоматизации тестирования.

Как объявляется декоратор? | PrepBro