python theading.Timer: how to pass argument to the callback?
Question:
I tried this code:
import threading
def hello(arg, kargs):
print(arg)
t = threading.Timer(2, hello, "bb")
t.start()
while 1:
pass
The output is just b
.
How can I pass arguments to the callback properly?
If I remove the kargs
parameter from hello
, I get an exception that says TypeError: hello() takes 1 positional argument but 2 were given
. Why? Where did the kargs
value come from in the first code?
Answers:
Timer
expects a sequence (normally, a list or tuple) of arguments and a mapping (normally, a dict) of keyword arguments, so pass a list instead:
import threading
def hello(arg):
print(arg)
t = threading.Timer(2, hello, ["bb"])
t.start()
while 1:
pass
Since "bb"
is an iterable, the Timer
will iterate over it and use each element as a separate argument; threading.Timer(2, hello, ["bb"])
is equivalent to threading.Timer(2, hello, ["b", "b"])
.
Use a dictionary to pass any keyword arguments to the callback, for example:
def hello(arg, kwarg):
print('arg is', arg, 'and kwarg is', kwarg)
t = threading.Timer(2, hello, ["bb"], {'kwarg': 1})
The third argument to Timer
is a sequence. Passing "bb"
as that sequence means that hello
gets the elements of that sequence ("b"
and "b"
) as separate arguments (arg
and kargs
). Put "bb"
in a list, and hello
will get the string as the first argument:
t = threading.Timer(2, hello, ["bb"])
Presumably, hello
was intended to have parameters like:
def hello(*args, **kwargs):
See What does ** (double star/asterisk) and * (star/asterisk) do for parameters? for a detailed explanation of this syntax.
I tried this code:
import threading
def hello(arg, kargs):
print(arg)
t = threading.Timer(2, hello, "bb")
t.start()
while 1:
pass
The output is just b
.
How can I pass arguments to the callback properly?
If I remove the kargs
parameter from hello
, I get an exception that says TypeError: hello() takes 1 positional argument but 2 were given
. Why? Where did the kargs
value come from in the first code?
Timer
expects a sequence (normally, a list or tuple) of arguments and a mapping (normally, a dict) of keyword arguments, so pass a list instead:
import threading
def hello(arg):
print(arg)
t = threading.Timer(2, hello, ["bb"])
t.start()
while 1:
pass
Since "bb"
is an iterable, the Timer
will iterate over it and use each element as a separate argument; threading.Timer(2, hello, ["bb"])
is equivalent to threading.Timer(2, hello, ["b", "b"])
.
Use a dictionary to pass any keyword arguments to the callback, for example:
def hello(arg, kwarg):
print('arg is', arg, 'and kwarg is', kwarg)
t = threading.Timer(2, hello, ["bb"], {'kwarg': 1})
The third argument to Timer
is a sequence. Passing "bb"
as that sequence means that hello
gets the elements of that sequence ("b"
and "b"
) as separate arguments (arg
and kargs
). Put "bb"
in a list, and hello
will get the string as the first argument:
t = threading.Timer(2, hello, ["bb"])
Presumably, hello
was intended to have parameters like:
def hello(*args, **kwargs):
See What does ** (double star/asterisk) and * (star/asterisk) do for parameters? for a detailed explanation of this syntax.