Декораторы с аргументами в Python на примерах
В этом уроке вы узнаете, как определять декораторы Python с аргументами, используя фабрику декораторов.
Декоратор с аргументами в Python
Предположим, у вас есть функция Say, которая выводит сообщение:
def say(message): ''' print the message Arguments message: the message to show ''' print(message)
и вы хотите выполнять функцию Say() 5 раз подряд каждый раз, когда вы ее вызываете. Например:
say('Hi')
Программа должна показать следующее сообщение Hi пять раз следующим образом:
Hi Hi Hi Hi Hi
Для этого можно использовать обычный декоратор:
@repeat def say(message): ''' print the message Arguments message: the message to show ''' print(message)
И вы можете определить декоратор повтора следующим образом:
def repeat(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(5): result = fn(*args, **kwargs) return result return wrapper
Ниже показан полный код:
from functools import wraps def repeat(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(5): result = fn(*args, **kwargs) return result return wrapper @repeat def say(message): ''' print the message Arguments message: the message to show ''' print(message) say('Hello')
Что делать, если вы хотите выполнить функцию say() десять раз. В этом случае вам необходимо изменить жестко запрограммированное значение 5 в декораторе повтора.
Однако это решение не является гибким. Например, вы хотите использовать декоратор повторения для выполнения функции 5 раз, а затем еще 10 раз. Повторяющийся декоратор не соответствует этому требованию.
Чтобы это исправить, вам нужно изменить декоратор повторения, чтобы он принимал аргумент, указывающий, сколько раз функция должна выполняться следующим образом:
@repeat(5) def say(message): ...
Чтобы определить декоратор повторения, функция restart(5) должна вернуть исходный декоратор.
def repeat(times): # return the original "repeat" decorator
Новая функция повторения возвращает декоратор. И ее часто называют фабрикой декораторов.
Следующая функция повторения возвращает декоратор:
def repeat(times): ''' call a function a number of times ''' def decorate(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(times): result = fn(*args, **kwargs) return result return wrapper return decorate
В этом коде функция декорирования является декоратором. Это эквивалент оригинального декоратора повторения.
Обратите внимание, что новая функция повторения не является декоратором. Это фабрика декораторов, которая возвращает декоратор.
Положим все это вместе.
from functools import wraps def repeat(times): ''' call a function a number of times ''' def decorate(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(times): result = fn(*args, **kwargs) return result return wrapper return decorate @repeat(10) def say(message): ''' print the message Arguments message: the message to show ''' print(message) say('Hello')