2

Let's say I want to execute any function repeatedly for 5 seconds. I can do something like this:

def any_function(name):
  print(f"hello {name}")
import time
timeout = 5   # [seconds]
timeout_start = time.time()
while time.time() < timeout_start + timeout:
  time.sleep(1) # optional, just to slow down execution
  any_function("id3a") #could be any function

what if I want to make this while loop available for other functions, I tried to use a decorator - see below - but it breaks the while loop after the first iteration.

def decorator_function(original_function):
  import time
  timeout = 5   # [seconds]
  timeout_start = time.time()
  while time.time() < timeout_start + timeout:
    def wrapper_function(*args, **kwargs):
      time.sleep(1) # optional, just to slow down execution
      return original_function(*args,**kwargs)
    return wrapper_function
  
@decorator_function
def any_function(name):
  print(f"hello {name}")
  
any_function("id3a")

How would you do it?

id3a
  • 118
  • 1
  • 7
  • 2
    Is it helpful? https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds – Eliran Turgeman Aug 14 '20 at 16:51
  • Sorry, check again @superbrain – id3a Aug 14 '20 at 17:14
  • @EliranTurgeman I think I got that part right, the problem here is how do I make it work for other functions, using I guess, a decorator – id3a Aug 14 '20 at 17:14
  • 1
    `return wrapper_function` here you are returning and breaking function execution of `decorator_function` at the end of your `while` loop. That is why it is only executing once. additionally, you are just redefining `wrapper_function` over the course of 5 seconds. That's another reason it's only getting called once. Place your while loop inside of the `wrapper_function` you are returning and remove the inner `return` and you should be fine. – Axe319 Aug 14 '20 at 17:16
  • Thank you @Axe319, now I understand the reason – id3a Aug 14 '20 at 17:21
  • Powerful abstractions – TheExorcist Feb 07 '22 at 08:34

1 Answers1

3

If you want to use a decorator, here is a working example:

import time


def scheduler(timeout=5, interval=0):
    def decorator(function):
        def wrapper(*args, **kwargs):
            timeout_start = time.time()
            while time.time() < timeout_start + timeout:
                time.sleep(interval)
                function(*args, **kwargs)
        return wrapper
    return decorator


@scheduler(timeout=5, interval=1)
def any_function(name):
    print(f'hello {name}')


any_function('id3a')

It gives the output:

hello id3a
hello id3a
hello id3a
hello id3a
hello id3a

If you want to create another function to call your function repeatedly, here is an example:

import time


def scheduler(function, timeout=5, interval=0):
    timeout_start = time.time()
    while time.time() < timeout_start + timeout:
        time.sleep(interval)
        function()


def any_function(name):
    print(f'hello {name}')


scheduler(lambda: any_function('id3a'), timeout=5, interval=1)

The output is:

hello id3a
hello id3a
hello id3a
hello id3a
hello id3a
Valentin Vignal
  • 6,151
  • 2
  • 33
  • 73