简体   繁体   中英

Confusion with subclassing a threading class, and inheritance

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. If I try to call MyThread._target I get an error. So it seems as if they are creating a completely new init . So why even call threading.Thread.__init__ if you are not going to inherit any attributes?

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

Now another aspect I was confused about was, when I attempted to access the ._target after super inheritance; the attribute wasn'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 here

    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()

OUTPUT:

<built-in function print>
test

Traceback:
custom.run()...........
print(self._target)
AttributeError: 'MyThread' object has no attribute '_target'[/python]

The example which calls Thread.__init__ is less general than it could be. Thread.__init__ does, in fact, take some parameters, but they all have default values, so strictly speaking, you don't have to call it with any arguments.

Thread.run essential does nothing except run the callable passed as the target option to Thread.__init__ . If you don't pass any such argument, there's no real need to call Thread.run ; the overridden method does all the actual work.

Note that when using super , it's important to accept and pass on unknown arguments, not so much because you want the Thread methods to get any required arguments, but because your class doesn't know what class's method might be called next. That is determined by the runtime time of self , not the subclass of Thread .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM