为什么在创建threading.Thread.__init__(self)
课程时我被迫使用super(ClassName, self).__init__()
或threading.Thread
?
例如:
class Threader(threading.Thread):
def __init__(self, _fp, _q):
threading.Thread.__init__(self)
self.path = _fp
self.queue = _q
def run(self):
# Do stuff
或
class Threader(threading.Thread):
def __init__(self, _fp, _q):
super(Threader, self).__init__()
self.path = _fp
self.queue = _q
def run(self):
# Do stuff
这两种方法都有效,并且大致相同。但是,如果我删除.__init__()
方法,我会在堆栈中收到:from thread.start(): thread.__init__() not called
。
不应该定义我自己的def __init__()
“替换”.__init__()
方法吗?
我已阅读this其他SO帖子并且与我的想法一致,但是会遇到相同的堆栈错误。
答案 0 :(得分:3)
考虑这个简化的例子:
class dog:
def __init__(self):
self.legs = 4
self.sound = 'woof'
class chihuahua(dog):
def __init__(self):
self.sound = 'yip'
# what's missing here?
我们创建了dog
的子类,名为chihuahua
。这个类的用户会合理地期望它在所有默认方面都像狗一样,除了我们已经覆盖的特定一个(它产生的声音)。但请注意,正如您所指出的,新的子类__init__
取代了基类__init__
。 完全取代。与C ++不同,在创建子类实例时,基类初始化代码是 not 自动调用。因此,当您创建self.legs = 4
时,行chihuahua()
永远不会运行。结果,这种类型的狗跑来跑去,却不知道它有多少腿。因此,你可以说它不是一个功能齐全的狗,如果它在试图执行复杂的技巧时摔倒,你不应该感到惊讶。
作为子类设计者,您有两种方法可以解决此问题。第一种是在子类中显式重新实现self.legs = 4
行。好吧,在这个例子中它可以正常工作,但它一般不是一个很好的选择,因为它违反了DRY原则,即使在你做确切地知道要编写什么代码的情况下以及如何维护它。在更复杂的示例中(例如您的Thread
子类),您可能赢得知道。第二个选项:显式调用超类初始值设定项并让它做它的事情。