loretoparisi
loretoparisi

Reputation: 16271

Simple Threading in Python3

In Python2 I was using this simple way to run a Thread an passing parameters via args:

import threading


class FuncThread(threading.Thread):
    '''
        it worked fine in Python2
    '''
    def __init__(self, target, *args):
        self._target = target
        self._args = args
        print( self._args )
        threading.Thread.__init__(self)
    def run(self, *args):
      print( self._args )
      self._target(*self._args)

def testThreading(say=''):
  print("I'm a thread %s" % say)

t = FuncThread(testThreading, 'hi')
t.start()

Now in Python3 this does not work anymore, and I'm getting

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "main.py", line 11, in run
    self._target(*self._args)
TypeError: 'NoneType' object is not callable

because in the run override the self._args are null. If I use the new syntax in Python3 it is

# this works fine in Python3
threading.Thread(target=testThreading, args=('Hello Thread!',)).start()

that works ok, so how to correctly override the run method?

Upvotes: 1

Views: 959

Answers (3)

Nikolas Stevenson-Molnar
Nikolas Stevenson-Molnar

Reputation: 4680

The base threading.Thread class uses self._target and self._args for its own purposes. Because you are calling the super __init__ without arguments, those are being set to None in the parent constructor. To fix this, simply remove your __init__ use keyword args when creating the instance, and let the default behavior do the job for you:

import threading

class FuncThread(threading.Thread):
    def run(self, *args):
      print( self._args )
      self._target(*self._args)

def testThreading(say=''):
  print("I'm a thread %s" % say)

t = FuncThread(target=testThreading, args=('hi',))
t.start()

If you want to keep your original constructor signature, then call the parent __init__ with the target and args arguments, in which case you don't need to set them explicitly yourself:

import threading

class FuncThread(threading.Thread):
    def __init__(self, target, *args):
        super().__init__(target=target, args=args)
    def run(self, *args):
      print( self._args )
      self._target(*self._args)

def testThreading(say=''):
  print("I'm a thread %s" % say)

t = FuncThread(testThreading, 'hi')
t.start()

Upvotes: 2

quamrana
quamrana

Reputation: 39354

This is a work-around for Python3:

class FuncThread(threading.Thread):
    def __init__(self, target, *args):
        self._xtarget = target
        self._args = args
        print( self._args )
        threading.Thread.__init__(self)
    def run(self, *args):
      print( self._args )
      self._xtarget(*self._args)

Upvotes: 1

Evhz
Evhz

Reputation: 9238

Try it as follows:

import threading


class FuncThread(threading.Thread):

    def __init__(self, target, *args):
      threading.Thread.__init__(self)
      self._target = target
      self._args = args
      print( self._args )

    def run(self, *args):
      print( self._args )
      self._target(*self._args)

def testThreading(say=''):
  print("I'm a thread %s" % say)

t = FuncThread(testThreading, 'hi')
t.start()

It happened to me before, to init parent class before any attempt on the child, in this case FuncThread ends up overriden.

Upvotes: 1

Related Questions