2015-06-18 13 views
5

Ich fand this Rate-limitierende Python Dekorator basierend auf redis Klassen. Wie kann ich einen ähnlichen Decorator schreiben, der nur das verwendet, was in der Standardbibliothek verfügbar ist, die wie folgt verwendet werden kann?Rate-limitierende Python Decorator

def ratelimit(limit, every): 
    # python magic 

@ratelimit(limit=1, every=2) 
def printlimited(x): 
    print x 

# print one number every two seconds 
for x in range(10): 
    printlimited(x) 

Es gibt andere answers auf Stackoverflow, aber sie erlauben nicht den Nenner zu spezifizieren.

Antwort

7

können Sie ein threading.Semaphore verwenden, um die Anfragen zu zählen und blockieren, die den Grenzwert überschreiten, mit threading.Timer in Kombination mit einer Funktion zu planen, die die Semaphore freigibt.

from threading import Semaphore, Timer 
from functools import wraps 

def ratelimit(limit, every): 
    def limitdecorator(fn): 
     semaphore = Semaphore(limit) 
     @wraps(fn) 
     def wrapper(*args, **kwargs): 
      semaphore.acquire() 
      try: 
       return fn(*args, **kwargs) 
      finally:     # don't catch but ensure semaphore release 
       timer = Timer(every, semaphore.release) 
       timer.setDaemon(True) # allows the timer to be canceled on exit 
       timer.start() 
     return wrapper 
    return limitdecorator 
+0

Das Semaphor wird nicht freigegeben, wenn die umbrochene Funktion eine Ausnahme auslöst. Sie können eine 'try..finally'-Klausel verwenden, um sicherzustellen, dass dies geschieht. –

+0

@PaulMFurley schöner Fang! Ich habe den Code bearbeitet. Würden Sie das überprüfen? –