Overriding python threading.Thread.run()
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()
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()
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."
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!
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