Python Forum
Confusion with sublcassing a threading class, and inheritance
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Confusion with sublcassing a threading class, and inheritance
#1
I am trying to understand how to subclass a Thread,
and I am confused with some details of inheritance.
It seems if I want to modify
the __init__ I need to call super as follows:




class MyThread(threading.Thread):
    def __init__(self, url, browser, *args, **kwargs):
        super(MyThread, self).__init__(*args, **kwargs)
        self.url = url
        self.browser = browser
This allows me to inherit all of the parents init
attributes as I am using *args, **kwargs and I can call MyThread._target within the initializer and it works.
However it seems I don't need to call super to
modify the run method. I have seen this example online:

class MyThread(threading.Thread):
 
    def __init__(self, number, logger):
        threading.Thread.__init__(self)
        self.number = number
        self.logger = logger
 
    def run(self):
        """
        Run the thread
        """
        #modification to run method but no call to it
        logger.debug('Calling doubler')
        doubler(self.number, self.logger)
Here it seems they are overwriting the parent init with The threading.Thread.__init__(self) ?
However, the threading.Thread.__init__(self) is not
calling any parameters, so it's essentially an empty __init__ and
doesn't acquire any of the parents attributes such as target, args, group.
So it seems as if they are creating a new init. So why even call threading.Thread.__init__ if you are not going to inherit any
attributes?

And why doesn't run require threading.Thread.run() if they are modifying the run method?
It seems only init is requiring the call to the original init



Now I was trying to access the ._target after super inheritance, but the attribute isn't found in the run method:

class MyThread(threading.Thread):
    def __init__(self, number, style, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.number = number
        self.style = style
        print(self._target) # works
    
    def run(self, *args, **kwargs):
        super().run(*args, **kwargs)
        print(self._target) # leads to error
        print('thread has ended')


   
custom = MyThread(target = print, number = 3, style ="red", args = ("test",))
 custom.run()
Error:
<built-in function print> test Traceback: custom.run() print(self._target) AttributeError: 'MyThread' object has no attribute '_target'[/python]
So these are the things I am confused about and am hoping someone can clarify these details.

Thank you.
Reply
#2
By doing
class MyThread(threading.Thread):
  
    def __init__(self, number, logger):
your init is overwriting the original init
both super(MyThread, self).__init__(*args, **kwargs) and threading.Thread.__init__(self)
call the original init.
it is sometime necessary to call an init with no given arguments because the init does other wanted things.

The following is threading.Thread init
def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs=None, *, daemon=None):
        """This constructor should always be called with keyword arguments. Arguments are:

        *group* should be None; reserved for future extension when a ThreadGroup
        class is implemented.

        *target* is the callable object to be invoked by the run()
        method. Defaults to None, meaning nothing is called.

        *name* is the thread name. By default, a unique name is constructed of
        the form "Thread-N" where N is a small decimal number.

        *args* is the argument tuple for the target invocation. Defaults to ().

        *kwargs* is a dictionary of keyword arguments for the target
        invocation. Defaults to {}.

        If a subclass overrides the constructor, it must make sure to invoke
        the base class constructor (Thread.__init__()) before doing anything
        else to the thread.

        """
        assert group is None, "group argument must be None for now"
        if kwargs is None:
            kwargs = {}
        self._target = target
        self._name = str(name or _newname())
        self._args = args
        self._kwargs = kwargs
        if daemon is not None:
            self._daemonic = daemon
        else:
            self._daemonic = current_thread().daemon
        self._ident = None
        self._tstate_lock = None
        self._started = Event()
        self._is_stopped = False
        self._initialized = True
        # sys.stderr is not stored in the class like
        # sys.exc_info since it can be changed between instances
        self._stderr = _sys.stderr
        # For debugging and _after_fork()
        _dangling.add(self)
with the run method you only call its super if you want the original run to work, the reason you cant call self._target
is because you are calling the original run method which if you take a look at it theres a del self._target, self._args, self._kwargs at the end.
 def run(self):
        """Method representing the thread's activity.

        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.

        """
        try:
            if self._target:
                self._target(*self._args, **self._kwargs)
        finally:
            # Avoid a refcycle if the thread is running a function with
            # an argument that has a member that points to the thread.
            del self._target, self._args, self._kwargs
you don't want this behaviour so don't call super on the original run method
Reply
#3
You were almost right.
The super call in the init method is right, the super call in the run method is wrong.
You are overriding the run method. The original run calls the function _target.
In your case this attribute is empty, because you have not set it.
You're going the way to overload the run method with your own code.

The run method should never called directy. The start method of the original class Thread does this.
This is the funny part. The original start method calls the overridden run method of the child class.

class MyThread(threading.Thread):
    def __init__(self, number, style, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.number = number
        self.style = style
        print(self._target) # works
        # Your target is empty, the run method is called by start
     
    def run(self, *args, **kwargs):
        """
        This method should not called directly.
        Use the start() method.
        """
        # target is still empty, because it's not set
        print(self._target) # leads to error
        print('thread has ended')
Output:
In [19]: MyThread(1,2).start() None None thread has ended In [20]:
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  super() and order of running method in class inheritance akbarza 7 594 Feb-04-2024, 09:35 AM
Last Post: Gribouillis
  Concurrent futures threading running at same speed as non-threading billykid999 13 1,715 May-03-2023, 08:22 AM
Last Post: billykid999
  Child class inheritance issue eakanathan 3 1,299 Apr-21-2022, 12:03 PM
Last Post: deanhystad
  Tutorials on sockets, threading and multi-threading? muzikman 2 2,076 Oct-01-2021, 08:32 PM
Last Post: muzikman
  Importing issues with base class for inheritance riccardoob 5 4,589 May-19-2021, 05:18 PM
Last Post: snippsat
  3D vector class with inheritance from 2D vector class buss0140 4 3,074 Dec-20-2020, 08:44 PM
Last Post: deanhystad
  Class inheritance oclmedyb 3 2,212 Dec-09-2020, 04:43 PM
Last Post: deanhystad
  Can we access instance variable of parent class in child class using inheritance akdube 3 13,886 Nov-13-2020, 03:43 AM
Last Post: SalsaBeanDip
  Performance degradation with IO class inheritance wsygzyx 2 2,090 Jun-18-2020, 06:02 PM
Last Post: wsygzyx
  threading for method outside class anna 0 1,368 Nov-17-2019, 07:05 AM
Last Post: anna

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020