Reputation: 3415
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
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
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
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
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