Декораторы с аргументами в 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')
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *