kbb
kbb

Reputation: 3415

Executing a function (with a parameter) every X seconds in python

I want to run a code that runs a function with a parameter (eg. greet(h)) every 5 seconds. I tried using threading but it doesn't work. It executes just once. See the code below and the errors:

import threading

oh_hi = "Hi guys"

def greeting(hello):
    print "%s" % hello



threading.Timer(1, greeting(oh_hi)).start()

Error shown below:

> >>> ================================ RESTART
> ================================
> >>>  Hi guys
> >>> Exception in thread Thread-1: Traceback (most recent call last):  
> File "C:\Python27\lib\threading.py",
> line 530, in __bootstrap_inner
>     self.run()   File "C:\Python27\lib\threading.py", line
> 734, in run
>     self.function(*self.args, **self.kwargs) TypeError: 'NoneType' object is not callable

Kindly assist.

Thanks

Upvotes: 4

Views: 8155

Answers (4)

martineau
martineau

Reputation: 123393

As others have pointed out, the error is because you're not passing the proper arguments to the threading.Timer() method. Correcting that will run your function, once, after 5 seconds. There are a number of ways to get it to repeat.

An object-oriented approach would be to derive a new threading.Thread subclass. While it would be possible to create one that does specifically what you want -- namely print "%s" % hello -- it's only slightly more difficult to craft a more generic, parameterized, subclass that will call a function passed to it during its instantiation (just like threading.Timer()). This is illustrated below:

import threading
import time

class RepeatEvery(threading.Thread):
    def __init__(self, interval, func, *args, **kwargs):
        threading.Thread.__init__(self)
        self.interval = interval  # seconds between calls
        self.func = func          # function to call
        self.args = args          # optional positional argument(s) for call
        self.kwargs = kwargs      # optional keyword argument(s) for call
        self.runable = True
    def run(self):
        while self.runable:
            self.func(*self.args, **self.kwargs)
            time.sleep(self.interval)
    def stop(self):
        self.runable = False

def greeting(hello):
    print hello

thread = RepeatEvery(3, greeting, "Hi guys")
print "starting"
thread.start()
thread.join(21)  # allow thread to execute a while...
thread.stop()
print 'stopped'

Output:

# starting
# Hi guys
# Hi guys
# Hi guys
# Hi guys
# Hi guys
# Hi guys
# Hi guys
# stopped

Besides overriding the base threading.Thread class's __init__() and run() methods, a stop() method was added to allow the thread to be terminated when desired. I also simplified the print "%s" % hello in your greeting() function to just print hello.

Upvotes: 4

Manuel Salvadores
Manuel Salvadores

Reputation: 16525

You need to pass the parameter oh_hi as a paramater itself to threading.Timer ... as stated in the documentation ...

threading.Timer(interval, function, args=[], kwargs={})

To fix it you'd do ...

import threading

def greeting(hello):
    print "%s" % hello

if __name__ == "__main__":
    oh_hi = "Hi guys"
    threading.Timer(1, greeting, args=(oh_hi,)).start()

Upvotes: 3

eumiro
eumiro

Reputation: 212835

threading.Timer(1, greeting(oh_hi)).start()

needs a function as the second parameter. Your code gives it None (the return value of the function greeting(hello). You should use:

threading.Timer(1, greeting).start()

which however ignores the oh_hi parameter.

Reading the documentation suggests:

threading.Timer(1, greeting, args=[oh_hi]).start()

Upvotes: 0

Andrea Spadaccini
Andrea Spadaccini

Reputation: 12651

import time

def greeting(hello):
    print "%s" % hello

while True:
    greeting(oh_hi)
    time.sleep(5)

If you want to use threading.Timer, keep in mind that you have to pass the parameter in this way (see the docs):

threading.Timer(1, greeting, (oh_hi,)).start()

The problem with your code is that greeting(oh_hi) is evaluated when the Timer object is being built. The function is executed but has no return value, and None becomes the second argument of Timer, that of course complains that None is not callable.

Upvotes: 0

Related Questions