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
# Привет Юля!