应该调用父类的__ init__()吗?

在 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__

177038 次浏览

编辑 : (在代码更改之后)
我们没有办法告诉您是否需要调用您父母的 __init__(或任何其他函数)。遗产继承显然不需要这样的要求。这完全取决于代码的逻辑: 例如,如果所有的 __init__都是在父类中完成的,那么完全可以跳过子类 __init__

考虑以下例子:

>>> class A:
def __init__(self, val):
self.a = val




>>> class B(A):
pass


>>> class C(A):
def __init__(self, val):
A.__init__(self, val)
self.a += val




>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12

没有硬性规定。类的文档应该指明子类是否应该调用超类方法。有时候你想完全替换超类的行为,有时候你想扩展它——比如在超类调用之前和/或之后调用你自己的代码。

更新: 同样的基本逻辑适用于任何方法调用。构造函数有时需要特别考虑(因为它们通常设置决定行为的状态)和析构函数,因为它们并行构造函数(例如在资源分配中,例如数据库连接)。但同样的情况也可能适用于小部件的 render()方法。

更新: 什么是 OPP?你是说 OOP 吗?子类通常需要知道 什么的关于超类的设计。不是内部实现的细节——而是超类与其客户机(使用类)之间的基本契约。这在任何方面都没有违反 OOP 原则。这就是为什么 protected在 OOP 中通常是一个有效的概念(当然,在 Python 中并非如此)。

在 Python 中,调用超类的 __init__是可选的。如果调用它,那么是否使用 super标识符或者是否显式命名超类也是可选的:

object.__init__(self)

对于对象,严格来说并不需要调用 super 方法,因为 super 方法是空的。__del__也是。

另一方面,对于 __new__,您确实应该调用 super 方法,并将其返回值用作新创建的对象——除非您显式地希望返回不同的内容。

我觉得,你应该叫它。如果您的超类是 object,那么您不应该这样做,但是在其他情况下,我认为不调用它是例外的。正如其他人已经回答的那样,如果您的类甚至不需要重写 __init__本身,这是非常方便的,例如当它没有(额外的)内部状态需要初始化时。

如果你需要从 super 的 __init__做一些事情,除了在当前类的 __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__.

匿名的回答是:
“如果你需要从 super 的 __init__中做一些事情,除了当前类的 __init__中正在做的事情之外,你必须自己调用它,因为这不会自动发生”

令人难以置信: 他的措辞完全违背了继承的原则。


不是 “超级 __init__(...)的某些事情不会自动发生”,而是它会自动发生,但是它不会发生,因为基类的 __init__被派生类 __init__的定义覆盖

那么,为什么要定义一个派生类的 __init__,因为它覆盖了当某人诉诸继承时的目标?

这是因为我们需要定义一些在基类的 __init__中没有执行的操作,而获得这些操作的唯一可能性就是将其执行放在派生类的 __init__函数中。
换句话说,如果基类的 __init__没有被覆盖,那么 在基类的 __init__中还需要一些东西就会自动执行。
恰恰相反。


然后,问题是基类的 __init__中所需的指令在实例化时不再被激活。为了抵消这种失活,需要一些特殊的东西: 显式调用基类“ __init__”,以便 留着吧,NOT TO ADD,即基类“ __init__”执行的初始化。 这正是官方文件所说的:

派生类中的重写方法实际上可能希望 < strong > 扩展 而不是简单地替换同名的基类方法 。 有一种直接调用基类方法的简单方法: just 调用 BaseClassName.methodname (self,reference)。
Http://docs.python.org/tutorial/classes.html#inheritance

故事就是这样的:

  • 当目标是保持基类执行的初始化时,即纯继承,不需要特殊的东西,只需要避免在派生类中定义 __init__函数

  • 当目标是替换基类执行的初始化时,必须在派生类中定义 __init__

  • 当目标是为基类执行的初始化添加进程时,必须定义一个派生类的 __init__,包括对基类 __init__的显式调用


我在 Anon 的帖子中感到惊讶的是,他不仅表达了与遗传理论相反的观点,而且已经有5个家伙从那里经过,而且没有一个人对这个有意思的话题做出反应,这个话题必须相对频繁地阅读。

是的,您应该总是显式地调用基类 __init__作为一种良好的编码实践。忘记这样做可能会导致微妙的问题或运行时错误。即使 __init__不采用任何参数,也是如此。这不同于其他编译器会为您隐式调用基类构造函数的语言。巨蟒不@么做!

总是调用基类 _init__的主要原因是,基类通常可以创建成员变量并将其初始化为默认值。因此,如果不调用基类 init,那么将不会执行任何代码,最终得到的基类将没有成员变量。

例子 :

class Base:
def __init__(self):
print('base init')


class Derived1(Base):
def __init__(self):
print('derived1 init')


class Derived2(Base):
def __init__(self):
super(Derived2, self).__init__()
print('derived2 init')


print('Creating Derived1...')
d1 = Derived1()
print('Creating Derived2...')
d2 = Derived2()

这些指纹。

Creating Derived1...
derived1 init
Creating Derived2...
base init
derived2 init

运行此代码