Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass class attributes into method decorators?

I am trying to make a class that will make api requests, retrying based on configuration options passed in to the retrying.retry decorator, and handle different error codes in the correct way for each job.

Here is my code:

from retrying import retry


class APIRequester:
    def __init__(self, url, **kwargs):
        self.url = url
        self.retry_kwargs = kwargs


    @retry(**self.retry_kwargs) # Obviously doesn't know what self is
    def make_request(self):
        pass

How can I pass in parameters to this method decorator? I tried making them a class attribute, which didn't work either.

like image 384
flybonzai Avatar asked Nov 02 '25 09:11

flybonzai


1 Answers

A couple of notes/questions:

  1. The @retry decorator will be applied to the make_request method at the time the class is created, while retry_kwargs will only become available when an instance of the class is created, and thus the former must precede the latter.

In which case, the former cannot depend on information that becomes available in the latter, ... as long as you use the decorator syntax ...

  1. The decorator syntax

     @decorator
         def xxx(...):
         ...
    

    is just syntax sugar for

     def xxx(...):
         ...
     xxx = decorate(xxx)
    

which means that, along with the fact that Python is very dynamic, you could force the issue by doing something like

    class APIRequester:
        def __init__(self, url, **kwargs):
            self.url = url
            self.retry_kwargs = kwargs
            APIRequester.make_request = retry(**kwargs)(APIRequester.make_request)

        def make_request(self):
            pass

Whether this particular decorator chokes on the self parameter or not, I cannot tell you.

Will you have more than one instance of APIRequester? If so, note that the method will be re-decorated each time a new instance is created: can this work sensibly? (I doubt it.) But see the edit below ...

If you do not have more that one instance, then you probably don't need to rely on information that becomes availale at the singleton's construction time.

The above were some general Python principles. I doubt that you really want to force the issue in this case. It seems to me that you are trying to use the decorator in a way that it was not designed to be used.

Edit: instancemethods

If you replace the line that does the decorating in the constructor with

self.make_request = retry(**kwargs)(self.make_request)

then each instance will get its own decorated version of the function. This should avoid any problems with re-decoration of the same function. There may will still be problems with self getting in the way. In that case, you could remove the self parameter from the definition and wrap it with staticmethod:

self.make_request = retry(**kwargs)(staticmethod(self.make_request))

Or better still, use decorator syntax to apply staticmethod to make_request at the place where you define it, the way Guido inteded it.

Like this, it even stands a chance of working! :-)

like image 126
jacg Avatar answered Nov 03 '25 23:11

jacg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!