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...
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.
- 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...
- 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...
- 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...
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.
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...
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.
- 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...
- 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...
- 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...
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.