首页 > 解决方案 > 与子类化线程类和继承混淆

问题描述

我试图了解如何对线程进行子类化,但我对继承的一些细节感到困惑。看来如果我想修改__init__我需要调用 super 如下:

class MyThread(threading.Thread):
    def __init__(self, url, browser, *args, **kwargs):
        super(MyThread, self).__init__(*args, **kwargs)
        self.url = url
        self.browser = browser

这使我可以在使用时继承所有父级 init 属性,并且可以在初始化程序*args, **kwargs中调用它并且它可以工作。MyThread._target

但是似乎我不需要调用 super 来修改 run 方法。我在网上看过这个例子:

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)

在这里,他们似乎正在用 The threading.Thread.__init__(self) 覆盖父初始化?但是,threading.Thread.__init__(self)它没有调用任何参数,所以它本质上是一个空的__init__,并且没有获取任何父属性,例如目标、参数、组。如果我尝试打电话MyThread._target,我会收到错误消息。因此,他们似乎正在创建一个全新的init. threading.Thread.__init__那么,如果您不打算继承任何属性,为什么还要打电话呢?

threading.Thread.run()如果他们正在修改 run 方法,为什么 run 方法不需要调用原始 方法?似乎只有 init 需要调用原始 init 进行修改,但 run 不需要这样做。

现在我感到困惑的另一个方面是,当我尝试访问._targetafter 超级继承时;在 run 方法中找不到该属性:

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

输出:

<built-in function print>
test

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

标签: pythonmultithreadingoopinheritancesubclassing

解决方案


调用的示例Thread.__init__不如它可能的通用。Thread.__init__实际上,确实接受了一些参数,但它们都有默认值,所以严格来说,您不必使用任何参数调用它。

Thread.run除了运行作为target选项传递给Thread.__init__. 如果您不传递任何此类参数,则没有真正需要调用Thread.run; 被覆盖的方法完成所有实际工作。

请注意,在使用 时super,接受和传递未知参数很重要,不是因为您希望Thread方法获取任何必需的参数,而是因为您的类不知道接下来可能调用哪个类的方法。这取决于 的运行时间self,而不是 的子类Thread


推荐阅读