Reputation: 4691
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?
Upvotes: 49
Views: 79446
Reputation: 42638
You really don't need to subclass Thread.
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()
Upvotes: 83
Reputation: 21
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()
Upvotes: 2
Reputation: 141
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')
Upvotes: 2
Reputation: 4691
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()
Upvotes: 13
Reputation: 489
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."
Upvotes: 10
Reputation: 3080
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
Upvotes: 4
Reputation: 2889
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!
Upvotes: 5
Reputation: 38136
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.
Upvotes: 0