__init__()应该调用父类的__init__()吗?

153 投票
7 回答
187478 浏览
提问于 2025-04-15 14:06

我习惯在Objective-C中使用这样的结构:

- (void)init {
    if (self = [super init]) {
        // init class
    }
    return self;
}

那么在Python中,__init__方法是否也应该调用父类的实现呢?

class NewClass(SomeOtherClass):
    def __init__(self):
        SomeOtherClass.__init__(self)
        # init class

对于__new__()__del__(),这个说法也是对的吗?

编辑:这里有一个非常相似的问题:Python中的继承和重写__init__

7 个回答

134

在Anon的回答中:
“如果你需要在当前类的__init__中做的事情之外,还需要做一些来自父类__init__的事情,你必须自己调用它,因为这不会自动发生。”

这真是不可思议:他说的正好和继承的原则相反。


并不是说“来自父类__init__的某些东西不会自动发生”,而是说它本来会自动发生,但因为子类的__init__覆盖了父类的__init__,所以它没有发生。

那么,为什么要定义子类的__init__呢?因为它覆盖了继承时想要的东西呀?

其实是因为我们需要在父类的__init__中没有做的事情,而唯一能做到这一点的方法就是把这些操作放在子类的__init__函数里。
换句话说,我们需要在父类的__init__中做一些事情,而这些事情本来会在父类的__init__中自动完成,如果没有被覆盖的话。
而不是相反。


所以,问题在于,父类的__init__中想要的指令在实例化时不再被激活。为了弥补这个问题,需要做一些特别的事情:显式地调用父类的__init__,以保持,而不是添加,父类__init__所做的初始化。这正是官方文档中所说的:

在子类中覆盖的方法实际上可能想要扩展而不是简单替换同名的父类方法。调用父类方法有一个简单的方法:直接调用BaseClassName.methodname(self, arguments)。
http://docs.python.org/tutorial/classes.html#inheritance

这就是整个故事:

  • 当目的是保持父类的初始化时,这就是纯粹的继承,不需要特别的操作,只需避免在子类中定义__init__函数。

  • 当目的是替换父类的初始化时,必须在子类中定义__init__

  • 当目的是在父类的初始化基础上添加过程时,必须在子类中定义__init__,并显式调用父类的__init__


我觉得Anon的帖子令人惊讶的不仅是他表达了与继承理论相反的观点,还有五个人毫不犹豫地点赞,而在这个有趣的话题上,两年内竟然没有人反应。

163

如果你在当前类的 __init__ 方法中需要执行一些来自父类(super)的 __init__ 方法的操作,你必须自己去调用它,因为这不会自动发生。不过,如果你不需要父类的 __init__ 方法里的东西,那就不需要去调用它。举个例子:

>>> class C(object):
        def __init__(self):
            self.b = 1


>>> class D(C):
        def __init__(self):
            super().__init__() # in Python 2 use super(D, self).__init__()
            self.a = 1


>>> class E(C):
        def __init__(self):
            self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

对于 __del__ 方法也是一样的(但要注意,不要过于依赖 __del__ 来进行清理工作,建议使用 with 语句来处理)。

我很少使用 __new__ 方法,通常我会把所有的初始化工作放在 __init__ 方法里。

71

在Python中,调用父类的 __init__ 方法是可选的。如果你选择调用它,那么使用 super 这个关键词也是可选的,或者你可以直接写出父类的名字。

object.__init__(self)

对于对象来说,调用父类的方法并不是绝对必要的,因为父类的方法是空的。__del__ 方法也是如此。

另一方面,对于 __new__ 方法,你确实应该调用父类的方法,并把它的返回值作为新创建的对象,除非你想返回其他的东西。

撰写回答