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

时间:2009-09-06 14:04:23

标签: python

我在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__(),这也是真/假吗?

修改:有一个非常相似的问题:Inheritance and Overriding __init__ in Python

7 个答案:

答案 0 :(得分:125)

除了当前班级__init__中的内容之外,如果你需要超级__init__,的内容,你必须自己调用它,因为这不会自动发生。但是,如果你不需要来自super __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__.

中进行了所有初始化

答案 1 :(得分:83)

在Anon的回答中:
 “如果除了当前班级__init__中的内容之外,你需要完成超级__init__的某些内容,你必须自己调用它,因为这不会自动发生”

令人难以置信的是:他的措辞完全与继承原则相反。


不是“来自超级__init__(...)的东西不会自动发生”,它会自动发生,但它不会发生,因为基类'__init__被derived-clas的定义覆盖__init__

那么,为什么定义一个derived_class'__init__,因为它会覆盖当某人诉诸继承时的目标?

这是因为需要定义一些未在基类“__init__中完成的东西,并且获得它的唯一可能性是将其执行放在派生类”__init__函数中。
换句话说,一个人需要在基类“__init__”中添加的内容,如果后者未被覆盖,则需要在base-classe'__init__中自动完成。 。
 不相反。


然后,问题是基类“__init__中存在的所需指令在实例化时不再被激活。为了抵消这种失活,需要一些特殊的东西:明确调用基类“__init__,以便 KEEP ,而不是添加,由基类执行的初始化” __init__。 这正是官方文件中所说的:

  

派生类中的重写方法实际上可能需要扩展   而不是简单地替换相同名称的基类方法。   有一种简单的方法可以直接调用基类方法:只是   调用BaseClassName.methodname(self,arguments)。
  http://docs.python.org/tutorial/classes.html#inheritance

这就是故事:

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

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

  • 当目标是将进程添加到基类执行的初始化时,必须定义派生类'__init__,包括对基类{{1}的显式调用}


我在Anon的帖子中感到惊讶的不仅仅在于他表达了与继承理论相反的观点,而且还有5个人在没有转过头发的情况下匆匆过去,而且还没有人能够做出反应2年线程必须经常阅读其有趣的主题。

答案 2 :(得分:59)

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

object.__init__(self)

对于object,调用super方法并不是绝对必要的,因为super方法是空的。与__del__相同。

另一方面,对于__new__,你应该确实调用super方法,并将其返回作为新创建的对象 - 除非你明确想要返回不同的东西。

答案 3 :(得分:18)

修改 :(代码更改后)
我们无法告诉您是否需要致电您父母的__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

答案 4 :(得分:4)

没有硬性规定。类的文档应该指示子类是否应该调用超类方法。有时你想要完全取代超类行为,并在其他时候增加它 - 即在超类调用之前和/或之后调用你自己的代码。

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

进一步更新:什么是OPP?你的意思是OOP?不 - 一个子类经常需要知道关于超类设计的某些东西。不是内部实现细节 - 而是超类与其客户端(使用类)的基本合同。这不会以任何方式违反OOP原则。这就是为什么protected在OOP中是一个有效的概念(当然不是在Python中)。

答案 5 :(得分:4)

IMO,你应该打电话给它。如果您的超类是object,那么您不应该,但在其他情况下,我认为不应该调用它。正如其他人已经回答的那样,如果你的类甚至不必覆盖__init__本身,例如当它没有(额外的)内部状态来初始化时,这是非常方便的。

答案 6 :(得分:1)

是的,您应该始终显式调用基类__init__作为一种良好的编码习惯。忘记执行此操作可能会导致细微的问题或运行时错误。即使__init__不带任何参数也是如此。这与其他语言不同,在其他语言中,编译器会为您隐式调用基类构造函数。 Python不会那样做!

始终调用基类_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

Run this code

相关问题