This is a generalised version of: decorator-once-per-minute
@once_per_n(5) # for every 5 mins def add(a, b): return a + b # Which means... add = once_per_n(5)(add) # ^~~~~~~~~~~~^ this should return a function
How would you implement that? -> 3 levels of functions.
# Executes once, when we get an argument def once_per_n(n): # Executes once, when we decorate the function def middle(func): # <--- This is the decorated function, accepts no args last_invoked = 0 # Executes every time we invoke the function def wrapper(*args, **kargs): nonlocal last_invoked if time.time() - last_invoked < n: raise ... last_invoked = time.time() return fun(*args, **kargs) return wrapper return middle