Overriding python threading.Thread.run()

Question:

Given the Python documentation for Thread.run():

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

I have constructed the following code:

class DestinationThread(threading.Thread):
    def run(self, name, config):
        print 'In thread'

thread = DestinationThread(args = (destination_name, destination_config))
thread.start()

But when I execute it, I receive the following error:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 522, in __bootstrap_inner
    self.run()
TypeError: run() takes exactly 3 arguments (1 given)

It seems I am missing something obvious, but the various examples I have seen work with this methodology. Ultimately I am trying to just pass the string and dictionary into the thread, if the Constructor is not the right way, but rather to make a new function to set the values prior to starting the thread, I am open to that.

Any suggestions on how to best accomplish this?

Asked By: Gavin M. Roy

||

Answers:

You define the run method to accept 3 arguments, but you call it with one argument (python calls it with the reference to the object).

You need to pass the arguments to run instead of __init__.

Or make the __init__ method accept the arguments instead.

Answered By: Vasil

You really don’t need to subclass Thread. The only reason the API supports this is to make it more comfortable for people coming from Java where that’s the only way to do it sanely.

The pattern that we recommend you use is to pass a method to the Thread constructor, and just call .start().

 def myfunc(arg1, arg2):
     print 'In thread'
     print 'args are', arg1, arg2

 thread = Thread(target=myfunc, args=(destination_name, destination_config))
 thread.start()
Answered By: Jerub

The documentation of threading.Thread may seem to imply that any unused positional and keyword args are passed to run. They are not.

Any extra positional args and keyword kwargs are indeed trapped by the default threading.Thread.__init__ method, but they are ONLY passed to a method specified using target= keyword. They are NOT passed to the run() method.

In fact, the Threading documentation at makes it clear that it is the default run() method that invokes the supplied target= method with the trapped args and kwargs:

“You may override this method in a
subclass. The standard run() method
invokes the callable object passed to
the object’s constructor as the target
argument, if any, with sequential and
keyword arguments taken from the args
and kwargs arguments, respectively.”

Answered By: pjkundert

Here’s is an example of passing arguments using threading and not extending __init__:

import threading

class Example(threading.Thread):

    def run(self):
        print '%s from %s' % (self._Thread__kwargs['example'],
                              self.name)

example = Example(kwargs={'example': 'Hello World'})
example.start()
example.join()

And here’s an example using mutliprocessing:

import multiprocessing

class Example(multiprocessing.Process):

    def run(self):
        print '%s from %s' % (self._kwargs['example'],
                              self.name)

example = Example(kwargs={'example': 'Hello World'})
example.start()
example.join()
Answered By: Gavin M. Roy

If you want to keep your object-oriented approach and also have run arguments, you can do the following:

import threading
class Destination:
    def run(self, name, config):
        print 'In thread'

destination = Destination()
thread = threading.Thread(target=destination.run,
    args=(destination_name, destination_config))
thread.start()

As mentioned above, it could also be done with partial

from functools import partial
import threading
class Destination:
    def run(self, name, config):
        print 'In thread'

destination = Destination()
thread = threading.Thread(target=partial(
    destination.run, destination_name, destination_config))
thread.start()

The advantage of doing this versus a purely-functional approach is that it lets you keep your other existing object-oriented code the same. The only change is to have it not subclass Thread, which shouldn’t be a big deal, since per threading.Thread documentation:

only override the init() and run() methods of this class

If you were overriding Thread so that you could access the thread object from within your subclass, then I’d recommend just using threading.currentThread() from within your object. This way you segment the thread’s namespace from your own, and per the “Zen of Python” by Tim Peters:

Namespaces are one honking great idea — let’s do more of those!

Answered By: ihm

In order to address some of the confusion about whether an overridden run() method takes additional arguments, here is an implementation of an overridden run() method that does what the method inherited from threading.Thread does.

Note, this just to see how one would override run(); it is not meant to be a meaningful example. If all you want to do is invoking a target function with sequential and/or keyword arguments, it is not necessary to have a subclass; this has been pointed out e.g. in Jerub’s answer to this question.

The following code supports both Python v2 and v3.

Although particularly the access to the mangled attribute names in the Python 2 code is ugly, I am not aware of another way to access these attributes (let me know if you know one…):

import sys
import threading

class DestinationThread(threading.Thread):

    def run(self):
        if sys.version_info[0] == 2:
            self._Thread__target(*self._Thread__args, **self._Thread__kwargs)
        else: # assuming v3
            self._target(*self._args, **self._kwargs)

def func(a, k):
    print("func(): a=%s, k=%s" % (a, k))

thread = DestinationThread(target=func, args=(1,), kwargs={"k": 2})
thread.start()
thread.join()

It prints (tested with Python 2.6, 2.7, and 3.4 on Windows 7):

func(): a=1, k=2
Answered By: Andreas Maier

Since Thread constructor argument target is a callable, apply __call__ as the run method

class Worker(object):
  def __call__(self, name, age):
    print('name, age : ',name,age)

if __name__ == '__main__':

  thread = Thread(target=Worker(), args=('bob','50'))
  thread.start()

output :

('name, age : ', 'bob', '50')
Answered By: pmg7670

if you really need a subclass, you can use it like this

>>> class DestinationThread(threading.Thread):
    def __init__(self,name, config):
        super().__init__()
        self.name = name
        self.config = config
    def run(self):
        print("In thread")

you can access name and config by self.name & self.config

>>> thread = DestinationThread(destination_name, destination_config)
>>> thread.start()

it will give you the accepted output.

output:

In thread

or you can use, target parameter.

thread = Thread(target=some_func, args=[arg1, arg2])
thread.start()
Answered By: Anshu Gupta
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.