-
-
Save ChrisTM/5834503 to your computer and use it in GitHub Desktop.
class throttle(object): | |
""" | |
Decorator that prevents a function from being called more than once every | |
time period. | |
To create a function that cannot be called more than once a minute: | |
@throttle(minutes=1) | |
def my_fun(): | |
pass | |
""" | |
def __init__(self, seconds=0, minutes=0, hours=0): | |
self.throttle_period = timedelta( | |
seconds=seconds, minutes=minutes, hours=hours | |
) | |
self.time_of_last_call = datetime.min | |
def __call__(self, fn): | |
@wraps(fn) | |
def wrapper(*args, **kwargs): | |
now = datetime.now() | |
time_since_last_call = now - self.time_of_last_call | |
if time_since_last_call > self.throttle_period: | |
self.time_of_last_call = now | |
return fn(*args, **kwargs) | |
return wrapper |
Just in case anyone is wondering about the imports
from datetime import datetime, timedelta
from functools import wraps
I feel like it would be helpful to give some indication to the user that they are trying to call a function too soon. That could either be through some sort of logging or printing call, or raising an exception. I say this because I'd assume that if the caller is asking to execute a method, that they'd expect it to be executed.
Alternatively, add a wait
argument—if True
, wait the difference between time_since_last_call
and now
(or use a while loop to accommodate multi-threaded use cases), if False
, fail verbosely if the condition isn't met.
is this snippet threadsafe?
from datetime import datetime, timedelta
from functools import wraps
def throttle(seconds=0, minutes=0, hours=0):
throttle_period = timedelta(seconds=seconds, minutes=minutes, hours=hours)
def throttle_decorator(fn):
time_of_last_call = datetime.min
@wraps(fn)
def wrapper(*args, **kwargs):
now = datetime.now()
if now - time_of_last_call > throttle_period:
nonlocal time_of_last_call
time_of_last_call = now
return fn(*args, **kwargs)
return wrapper
return throttle_decorator
philer, yours is much messier - and, to top it off, it doesn't even work. Try running it.
MikeTam1021, maybe because nonlocal is from python3
The ratelimit package does this with a few extra features.
The ratelimit package does this with a few extra features.
Thanks - that is exactly what I needed!
Great little trick. Thanks!