Сообщить об ошибке.

Шаблон декоратора общего назначения

На основе этого шаблона можно строить декораторы общего назначения.

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # Что-то выполняется до 
        # вызова декорируемой функции
        ...
        ...
        ...
        value = func(*args, **kwargs)
        # декорируется возвращаемое значение 
        # функции или что-то выполняется после 
        # вызова декорируемой функции
        ...
        ...
        ...
        return value
    return wrapper

Примеры использования:

Следующий декоратор измеряет время работы функции и выводит длительность на консоль. Он вычисляет время непосредственно перед запуском функции и сразу после завершения функции. Время выполнения функции - это разница времени между окончанием работы функции и ее началом исполнения.

import functools, time

def timer(func):
    """Длительность работы функции"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        val = func(*args, **kwargs)
        end = time.perf_counter()
        work_time = end - start
        print(f"Время выполнения {func.__name__!r}: {work_time:.4f} сек.")
        return val
    return wrapper


@timer
def test(n):
    return sum([(i/55)**2 for i in range(n)])

x = test(1000)
print(f'Результат = {x}')
# Время выполнения 'test': 0.00007 сек.
# Результат = 110027.6033057851

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

import functools

def counter(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        wrapper.num += 1
        print(f'Вызов {func.__name__!r}: {wrapper.num}')
        val = func(*args, **kwargs)
        return val
    wrapper.num = 0
    return wrapper

@counter
def say(name):
    return f'Привет {name}!'

print(say('Андрей'))
print(say('София'))
print(say('Миша'))
print(say('Юля'))

# Вызов 'say': 1
# Привет Андрей!
# Вызов 'say': 2
# Привет София!
# Вызов 'say': 3
# Привет Миша!
# Вызов 'say': 4
# Привет Юля!