На основе этого шаблона можно строить декораторы общего назначения.
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 # Привет Юля!