Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing argurments to a decorator in python

I am using retry function from the package retrying. I want to pass the arguments of the retry decorator from a function and I am not sure how to achieve that.

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

I want to pass the arguments of retry when calling the post(). I know when the function is compiled, the resulting function object is passed to the decorator so I am not sure if this is possible- or if I should may be approach it differently.

like image 444
user2715898 Avatar asked Apr 20 '26 06:04

user2715898


2 Answers

If you just want to use the library as is, then you cannot really use the decorator like this. It's arguments are constant from when it is invoked (excepting messing about with mutable arguments). Instead, you could always invoke the decorator before calling the function each time. This allows you to change the retrying arguments as and when you need to.

eg.

def post(url, json):
    ...

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

But at that point, you might as well just skip the decorator altogether, and use what the decorator is using.

from retrying import Retrying

def post(url, json):
    ...

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

Either of these ways allow you to keep the post function pure and abstracted away from the concept of retrying (making it easier to call post when you don't want retrying behaviour).

You could also write a convenience function that wrapper that fills in defaults for your program. eg.

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=...)
like image 110
Dunes Avatar answered Apr 22 '26 22:04

Dunes


Generally speaking there no good ways to achieve this. You surely can write code like this:

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

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

and it will work. But it looks rather ugly and will construct decorated object for every call ("regular" decorators are executed once in import time).

If decorator itself is not very complex - you can use this approach in some more user-friendly manner:

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)
like image 33
Eugene Primako Avatar answered Apr 22 '26 21:04

Eugene Primako