Как работают декораторы? Напишите пример кастомного декоратора.python-5

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

Основная концепция

Декораторы работают на основе замыканий (closures) и возможности передавать функции как объекты. Когда вы применяете декоратор к функции, вы фактически заменяете оригинальную функцию на новую, которая может выполнять дополнительный код до или после вызова оригинальной функции.

Пример простого декоратора

Рассмотрим пример простого декоратора, который измеряет время выполнения функции:

import time

def timing_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

@timing_decorator
def some_function():
    time.sleep(2)
    print("Функция выполнена")

some_function()

В этом примере:

  1. timing_decorator — это декоратор, который принимает функцию func в качестве аргумента.
  2. Внутри декоратора определена новая функция wrapper, которая вызывает оригинальную функцию func и измеряет время её выполнения.
  3. Декоратор возвращает функцию wrapper, которая заменяет оригинальную функцию some_function.

Когда мы вызываем some_function(), на самом деле вызывается wrapper, которая выполняет дополнительный код (измерение времени) до и после вызова оригинальной функции.

Кастомный декоратор

Теперь создадим кастомный декоратор, который будет проверять, что аргументы функции являются положительными числами:

def positive_args_decorator(func):
    def wrapper(*args, **kwargs):
        for arg in args:
            if not isinstance(arg, (int, float)) or arg < 0:
                raise ValueError("Все аргументы должны быть положительными числами")
        return func(*args, **kwargs)
    return wrapper

@positive_args_decorator
def calculate_square(x):
    return x ** 2

print(calculate_square(5))  # 25
print(calculate_square(-5))  # ValueError: Все аргументы должны быть положительными числами

В этом примере:

  1. positive_args_decorator — это декоратор, который проверяет, что все аргументы функции являются положительными числами.
  2. Если хотя бы один аргумент не соответствует условию, выбрасывается исключение ValueError.
  3. Если все аргументы корректны, вызывается оригинальная функция func.

Резюмируем

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