I'm trying to make a RateLimiter class in Python that can be instantiated as a class property in other classes, and then applied to functions to be rate limited as a decorator. Here's the RateLimiter: import time from functools import wraps from threading import Lock class RateLimiter: def __init__(self, qps: float): self.qps = qps self.min_interval = 1.0 / qps self.last_call = 0.0 self.lock = Lock() def limit(self): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): with self.lock: now = time.monotonic() elapsed = now - self.last_call if elapsed < self.min_interval: time.sleep(self.min_interval - elapsed) self.last_call = time.monotonic() return func(*args, **kwargs) return wrapper return decorator I want to use it in a class like so class SomeWebClient: def __init__(self, qps: float = 10.0): self.rate_limiter = RateLimiter(qps=qps) @self.rate_limiter.limit() def some_api_call(self): # make some call to an API with a rate limit pass @self.rate_limiter.limit() def another_api_call(self): # make some call to an API with a rate limit pass But this doesn't work because self isn't defined for the @ decorator syntax. The only way I've been able to get this to work is by doing this: class SomeWebClient: def __init__(self, qps: float = 10.0): self.rate_limiter = RateLimiter(qps=qps) self.some_api_call = self.rate_limiter.limit()(self.some_api_call) self.another_api_call = self.rate_limiter.limit()(self.another_api_call) def some_api_call(self): # make some call to an API with a rate limit pass def another_api_call(self): # make some call to an API with a rate limit pass But this doesn't feel very clean. Is there a way to get it to work with the @ syntax, and not need to pass in state to the decorator function? I.e. I don't want every invocation of the decorator to require me passing in the QPS and the lock, I'd like that to be hidden away so that the decorator usage is clean. Or to take a step back, is there another way of implementing a RateLimiter without a decorator but is clean? I basically want an abstraction such that every instance of SomeWebClient has its own rate limiter, with potentially different QPS. And then I can mark methods I want to be rate limited cleanly. Continue reading...