Passing a python class constant to a decorator without self

Question:

I’m using the python ratelimit library and it uses a decorator to handle rate limiting of a function. I have a class constant I’d like to pass into the decorator but of course self wont work.

Is there a way to reference the UNIVERSALIS_MAX_CALLS_PER_SECOND constant within the decorator? Or, is there a clean, more appropriate way I should handle this?

Edit: I’m seeking to avoid globals. What I was hoping for was some python introspection maybe?

class Universalis():
    # FIXME: hard-coded North America
    API_ENDPOINT = "http://universalis.app/api/v2/North-America/"
    UNIVERSALIS_MAX_CALLS_PER_SECOND = 13 # 25 max
    UNIVERSALIS_MAX_CONNECTIONS = 6 # 8 max
    LISTINGS_PER_API_CALL = 500 # Universalis no max.

    @sleep_and_retry
    @limits(calls=self.UNIVERSALIS_MAX_CALLS_PER_SECOND, period=1)
    def fetch_and_process_item_listings(self, item_ids_querystring):
        # magic...
Asked By: Chris Cummings

||

Answers:

No, there is no way to access it there since the class is in middle of building itself, that means, you can not access it via self nor can you access it via class name. The only sensible option that you have got is to either move the variables into another class defined above this class or move the variables to global scope, You can also if you wish, move the variables in another module.

  1. Moving the variables to another class
# Notice how this class must always be placed above the class accessing it
class UniversalisConfig:
    # FIXME: hard-coded North America
    API_ENDPOINT = "http://universalis.app/api/v2/North-America/"
    UNIVERSALIS_MAX_CALLS_PER_SECOND = 13 # 25 max
    UNIVERSALIS_MAX_CONNECTIONS = 6 # 8 max
    LISTINGS_PER_API_CALL = 500 # Universalis no max.

class Universalis():
    @sleep_and_retry
    @limits(calls=UniversalisConfig.UNIVERSALIS_MAX_CALLS_PER_SECOND, period=1)
    def fetch_and_process_item_listings(self, item_ids_querystring):
        # magic...
  1. Moving the variable to global scope
# FIXME: hard-coded North America
API_ENDPOINT = "http://universalis.app/api/v2/North-America/"
UNIVERSALIS_MAX_CALLS_PER_SECOND = 13 # 25 max
UNIVERSALIS_MAX_CONNECTIONS = 6 # 8 max
LISTINGS_PER_API_CALL = 500 # Universalis no max.

class Universalis():
    @sleep_and_retry
    @limits(calls=UNIVERSALIS_MAX_CALLS_PER_SECOND, period=1)
    def fetch_and_process_item_listings(self, item_ids_querystring):
        # magic...
  1. Moving variables to a separate file

constants.py

# FIXME: hard-coded North America
API_ENDPOINT = "http://universalis.app/api/v2/North-America/"
UNIVERSALIS_MAX_CALLS_PER_SECOND = 13 # 25 max
UNIVERSALIS_MAX_CONNECTIONS = 6 # 8 max
LISTINGS_PER_API_CALL = 500 # Universalis no max.

in your Univarsalis file where you defined the class:

from . import constants  # Relative Import
# or
import constants  # Direct import

# Other magic...

class Universalis():
    @sleep_and_retry
    @limits(calls=constants.UNIVERSALIS_MAX_CALLS_PER_SECOND, period=1)
    def fetch_and_process_item_listings(self, item_ids_querystring):
        # magic...
Answered By: AmaanK

At the time limit is called, you have access to the name as an ordinary variable. Just drop the self..

class Universalis:
    API_ENDPOINT = "http://universalis.app/api/v2/North-America/"
    UNIVERSALIS_MAX_CALLS_PER_SECOND = 13
    UNIVERSALIS_MAX_CONNECTIONS = 6
    LISTINGS_PER_API_CALL = 500

    @sleep_and_retry
    @limits(calls=UNIVERSALIS_MAX_CALLS_PER_SECOND, period=1)
    def fetch_and_process_item_listings(self, item_ids_querystring):
        # magic...

Here’s a simple example that shows the "class attribute" used as a regular variable.

def d(n):
    print(n)
    def _(f):
        return f
    return _


class Foo:
    X = 5
    @d(X)
    def method(self):
        pass

When foo is defined, the decorator will print the value of Foo.X to standard output, since n receives the value of the variable X that will be used to define the class attribute.

Answered By: chepner
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.