0

I'm trying to write a decorator in Python to limit the number of times a function is called in an amount of time. I anticipate using it like this:

@ratelimit(seconds=15)
def foo():
    print 'hello'

start = time.time()
while time.time() - start < 10:
    foo()

> 'hello'
> 'hello'

So the decorated function can be called a maximum of once every seconds. In terms of implementing it I have this, but it doesn't work as I'm not sure the correct way to persist the last_call between subsequent calls:

import time

def ratelimit(seconds=10):

    last_call = None # Never call decorated function
    def decorator(func):


        def wrapper(*args, **kwargs):

            if last_call is None or time.time() - last_call > seconds:
                result = func(*args, **kwargs)
                last_call = time.time()
                return result

            return wraps(func)(wrapper)

    return decorator
nickponline
  • 25,354
  • 32
  • 99
  • 167

1 Answers1

3

The code below worked fine for me in python 2.7.

import time
from functools import wraps

last_called = dict()  # When last called, and with what result

def ratelimit(seconds=10, timer=time.time):
    def decorator(func):
        last_called[func] = None

        @wraps(func)
        def wrapper(*args, **kwargs):
            now = timer()
            call_data = last_called.get(func, None)
            if call_data is None or now - call_data[0] >= seconds:
                result = func(*args, **kwargs)
                last_called[func] = (now, result)
            else:
                result = call_data[1]  # Replay rate-limited result
            return result
        return wrapper
    return decorator
Jim
  • 1,161
  • 9
  • 21