-1

I'm trying to implement a decorator that allows to limit the rate with which a function is executed.

I would like the decorator to start a timer when the function is called. If the function is called before the timer runs out, I'd like to cancel the previous call and restart the timer. When the timer ends, the function should run.

I've serched around and found this decorator. However, this decorator stops the execution of the program while the timer is running, which is something I need to avoid.

How can I achieve this?

Luca
  • 1,610
  • 1
  • 19
  • 30

1 Answers1

1

this is rather complicated, but a simple idea is to start a timer thread and cancel it if the function is called again and start another timer thread.

now we need somewhere to store this timer ... so a dictionary should suffice, and to allow the user to choose the delay, we will just do a double wrap of functions.

from threading import Timer
from functools import wraps
import time

functions_store = {}
def main_decorator(interval):
    def sub_decorator(fun):
        function_id = id(fun)  # since no two objects have the same id
        @wraps(fun)
        def new_fun(*args,**kwargs):
            if function_id in functions_store:
                functions_store[function_id].cancel()  # cancel old timer
            new_timer = Timer(interval,fun,args=args,kwargs=kwargs)  # make new timer
            functions_store[function_id] = new_timer  # store timer to stop it later
            new_timer.start()
        return new_fun
    return sub_decorator


@main_decorator(1) # must be called again before 1 second passes.
def func_to_run():
    print("hi")
    
func_to_run()
time.sleep(0.5)
func_to_run()

the word "hi" will be printed after 1.5 seconds instead of 1 second because we called the function again before it fired the first time.

Ahmed AEK
  • 8,584
  • 2
  • 7
  • 23
  • I accepted this answer as it's exactly what I asked for. Unfortunately this does not work completely together within a `matplotlib` interactive plot that's where I needed it, but this is most likely a different problem and was not part of the question. – Luca Sep 29 '22 at 08:13