42

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?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Bin Chen
  • 61,507
  • 53
  • 142
  • 183

2 Answers2

84

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})
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • 1
    Here's a link to the [section on keyword arguments](http://docs.python.org/tutorial/controlflow.html#keyword-arguments) in a more up-to-date version of tutorial (although the information looks about the same). – martineau Dec 11 '10 at 09:26
  • 1
    Google kept dropping me in that version. Ironically, the older version is easier to read; they've gone so far overboard with the styling in the newer ones that it's distracting, with the background color spastically jumping back and forth. – Glenn Maynard Dec 11 '10 at 19:19
5

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.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
outis
  • 75,655
  • 22
  • 151
  • 221