передача аргументов декоратору в python - PullRequest
0 голосов
/ 25 июня 2018

Я использую функцию повтора из пакета повтор .Я хочу передать аргументы декоратора retry из функции, и я не уверен, как этого добиться.

@retry # (wait_exponential_multiplier=x,wait_exponential_max=y)
def post(url, json, exponential_multiplier, exponential_max):
    ...
    return(abc)

Я хочу передать аргументы retry при вызове post().Я знаю, что при компиляции function полученный объект function передается в decorator, поэтому я не уверен, возможно ли это- или если бы я мог подходить к этому по-другому.

Ответы [ 4 ]

0 голосов
/ 25 июня 2018

Это дополнение к ответам Жундиауса, показывающее, что вы даже можете использовать модуль проверки для правильной обработки подписи оформленной функции:

def deco_and_pass(deco, **kwparams):
    """Decorates a function with a decorator and parameter.
The parameters are passed to the decorator and forwarded to the function
The function must be prepared to receive those parameters, but they will
be removed from the signature of the decorated function."""
    def outer(f):
        sig = inspect.signature(f)       # remove parameters from the function signature
        params = collections.OrderedDict(sig.parameters)
        for k in kwparams:
            del params[k]
        def inner(*args, **kwargs):      # define the decorated function
            kwargs.update(kwparams)      # add the parameters
            # and call the function through the parameterized decorator
            return deco(**kwparams)(f)(*args, **kwargs)
        inner.__signature__ = inspect.signature(f).replace(
            parameters = params.values())
        inner.__doc__ = f.__doc__        # update doc and signature
        return inner
    return outer

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

@deco_and_pass(retry,wait_exponential_multiplier=x,wait_exponential_max=y)
def post(url, json, exponential_multiplier, exponential_max):
    ...
    return(abc)
...
post(url, json)

Подпись декорированной функции составляет всего def post(url, json)

Ограничения: приведенный выше код принимает и передает только ключевые аргументы для декоратора

0 голосов
/ 25 июня 2018

Если вы просто хотите использовать библиотеку как есть, тогда вы не сможете использовать декоратор, как этот.Его аргументы являются постоянными с момента его вызова (за исключением возни с изменяемыми аргументами).Вместо этого вы всегда можете вызвать декоратор перед каждым вызовом функции.Это позволяет вам изменять аргументы повторения, как и когда вам нужно.

например.

def post(url, json):
    ...

rety(post, wait_exponential_multiplier=...)(url=..., json=...)

Но в этот момент вы можете просто пропустить декоратор и использоватьдекоратор использует.

from retrying import Retrying

def post(url, json):
    ...

Retrying(wait_exponential_multiplier=...).call(post, url=..., json=...)

Любой из этих способов позволяет сохранить функцию post чистой и абстрагированной от концепции повторных попыток (что упрощает вызов post, когда вы этого не делаетехотите повторить попытку).

Вы также можете написать вспомогательную функцию, которая упаковывает значения по умолчанию для вашей программы.например,

def retrier(wait_exponential_multiplier=2, **kwargs):
    return Retrying(wait_exponential_multiplier=wait_exponential_multiplier, **kwargs)

retrier(wait_exponential_max=10).call(post, url=..., json=...)
retrier(wait_exponential_multiplier=3, wait_exponential_max=10).call(post, url=..., json=...)
0 голосов
/ 25 июня 2018

Вы должны создать новый декоратор, который передает свои собственные аргументы в декорированную функцию и преобразует функцию с помощью retry декоратора:

def retry_that_pass_down_arguments(**decorator_arguments):
    def internal_decorator(f):
        def decorated_function(*args, **kwargs):
            # Add the decorator key-word arguments to key-word arguments of the decorated function
            kwargs.update(decorator_arguments) 
            return retry(**decorator_arguments)(f)(*args, **kwargs) 
        return decorated_function
    return internal_decorator

Тогда вы можете простоделать:

@retry_that_pass_down_arguments(wait_exponential_multiplier=x, wait_exponential_max=y)
def post(url, json, exponential_multiplier=None, exponential_max=None):
    ...
    return(abc)
0 голосов
/ 25 июня 2018

Вообще говоря, нет хороших способов достичь этого. Вы наверняка можете написать код, подобный этому:

def post(url, json):
    ...
    return(abc)

...
decorated_func = retry(wait_exponential_max=1)(post)
a = decorated_func(url, json)

и это будет работать. Но это выглядит довольно некрасиво и будет создавать декорированный объект для каждого вызова («обычные» декораторы выполняются один раз за время импорта).

Если сам декоратор не очень сложен - вы можете использовать этот подход более удобным для пользователя способом:

def _post(url, json):
    return(abc)

def post(url, json, wait_exponential_max=None, **kwargs):
    return retry(wait_exponential_max=wait_exponential_max, **kwargs)(_post)(url, json)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...