[Python] How to use a class property as a decorator in Python?

Discussão em 'Python' iniciado por Stack, Maio 9, 2025.

  1. Stack

    Stack Membro Participativo

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

Compartilhe esta Página