简体   繁体   English

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

[英]Should __init__() call the parent class's __init__()?

I'm used that in Objective-C I've got this construct:我在 Objective-C 中使用过,我有这个结构:

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

Should Python also call the parent class's implementation for __init__ ? Python 是否也应该为__init__调用父类的实现?

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

Is this also true/false for __new__() and __del__() ?这对于__new__()__del__()也是对/错吗?

Edit: There's a very similar question: Inheritance and Overriding __init__ in Python编辑:有一个非常相似的问题: Inheritance and Overriding __init__ in Python

If you need something from super's __init__ to be done in addition to what is being done in the current class's __init__, you must call it yourself, since that will not happen automatically.如果除了当前类的__init__,中正在完成的操作之外,您还需要完成 super 的__init__中的某些操作,您必须自己调用它,因为这不会自动发生。 But if you don't need anything from super's __init__, no need to call it.但是如果你不需要来自 super 的__init__,的任何东西,就不需要调用它。 Example:例子:

>>> 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__ is the same way, (but be wary of relying on __del__ for finalization - consider doing it via the with statement instead). __del__是相同的方式,(但要警惕依赖__del__来完成 - 考虑通过 with 语句来完成)。

I rarely use __new__.我很少使用__new__. I do all the initialization in __init__.我在__init__.

In Anon's answer:在 Anon 的回答中:
"If you need something from super's __init__ to be done in addition to what is being done in the current class's __init__ , you must call it yourself, since that will not happen automatically" “如果除了当前类的__init__中正在做的事情之外,你还需要从 super 的__init__中完成一些事情,你必须自己调用它,因为那不会自动发生”

It's incredible: he is wording exactly the contrary of the principle of inheritance.令人难以置信:他的措辞与继承原则完全相反。


It is not that "something from super's __init__ (...) will not happen automatically" , it is that it WOULD happen automatically, but it doesn't happen because the base-class' __init__ is overriden by the definition of the derived-clas __init__这并不是说“来自 super 的__init__ (...) 的东西不会自动发生” ,而是它会自动发生,但它不会发生,因为基类的__init__被派生的定义覆盖了-类__init__

So then, WHY defining a derived_class' __init__ , since it overrides what is aimed at when someone resorts to inheritance??那么,为什么要定义一个 derived_class' __init__ ,因为它覆盖了某人求助于继承时的目标?

It's because one needs to define something that is NOT done in the base-class' __init__ , and the only possibility to obtain that is to put its execution in a derived-class' __init__ function.这是因为需要定义一些在基类的__init__中没有完成的事情,而获得它的唯一可能性是将其执行放在派生类的__init__函数中。
In other words, one needs something in base-class' __init__ in addition to what would be automatically done in the base-classe' __init__ if this latter wasn't overriden.换句话说,除了基类__init__中未被覆盖的情况下会自动完成的操作之外,还需要基类__init__中的某些内容。
NOT the contrary.不是相反。


Then, the problem is that the desired instructions present in the base-class' __init__ are no more activated at the moment of instantiation.然后,问题是基类__init__中存在的所需指令在实例化时不再被激活。 In order to offset this inactivation, something special is required: calling explicitly the base-class' __init__ , in order to KEEP , NOT TO ADD, the initialization performed by the base-class' __init__ .为了抵消这种失活,需要一些特殊的东西:显式调用基类' __init__ ,以便保持,而不是添加,由基类' __init__执行的初始化。 That's exactly what is said in the official doc:这正是官方文档中所说的:

An overriding method in a derived class may in fact want to extend rather than simply replace the base class method of the same name.派生类中的覆盖方法实际上可能想要扩展而不是简单地替换同名的基类方法 There is a simple way to call the base class method directly: just call BaseClassName.methodname(self, arguments).有一种直接调用基类方法的简单方法:调用 BaseClassName.methodname(self, arguments) 即可。
http://docs.python.org/tutorial/classes.html#inheritance http://docs.python.org/tutorial/classes.html#inheritance

That's all the story:这就是全部的故事:

  • when the aim is to KEEP the initialization performed by the base-class, that is pure inheritance, nothing special is needed, one must just avoid to define an __init__ function in the derived class当目标是保持基类执行的初始化时,即纯继承,不需要什么特别的,必须避免在派生类中定义__init__函数

  • when the aim is to REPLACE the initialization performed by the base-class, __init__ must be defined in the derived-class当目标是替换基类执行的初始化时,必须在派生类中定义__init__

  • when the aim is to ADD processes to the initialization performed by the base-class, a derived-class' __init__ must be defined, comprising an explicit call to the base-class __init__当目标是将进程添加到基类执行的初始化时,必须定义派生类的__init__ ,包括对基类__init__的显式调用


What I feel astonishing in the post of Anon is not only that he expresses the contrary of the inheritance theory, but that there have been 5 guys passing by that upvoted without turning a hair, and moreover there have been nobody to react in 2 years in a thread whose interesting subject must be read relatively often. Anon的帖子让我感到震惊的不仅是他表达了与继承论相反的观点,而且有5个路过的人毫不动摇地投票,而且2年内没有人回应必须相对经常阅读其有趣主题的线程。

In Python, calling the super-class' __init__ is optional.在 Python 中,调用超类的__init__是可选的。 If you call it, it is then also optional whether to use the super identifier, or whether to explicitly name the super class:如果你调用它,那么是否使用super标识符,或者是否显式命名超类也是可选的:

object.__init__(self)

In case of object, calling the super method is not strictly necessary, since the super method is empty.在对象的情况下,调用 super 方法并不是绝对必要的,因为 super 方法是空的。 Same for __del__ . __del__一样。

On the other hand, for __new__ , you should indeed call the super method, and use its return as the newly-created object - unless you explicitly want to return something different.另一方面,对于__new__ ,你确实应该调用 super 方法,并将它的返回值用作新创建的对象——除非你明确想要返回不同的东西。

Edit : (after the code change)编辑:(代码更改后)
There is no way for us to tell you whether you need or not to call your parent's __init__ (or any other function).我们无法告诉您是否需要调用您父母的__init__ (或任何其他函数)。 Inheritance obviously would work without such call.如果没有这样的调用,继承显然会起作用。 It all depends on the logic of your code: for example, if all your __init__ is done in parent class, you can just skip child-class __init__ altogether.这完全取决于您的代码逻辑:例如,如果您所有的__init__都在父类中完成,您可以完全跳过子类__init__

consider the following example:考虑以下示例:

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

There's no hard and fast rule.没有硬性规定。 The documentation for a class should indicate whether subclasses should call the superclass method.类的文档应该指出子类是否应该调用父类的方法。 Sometimes you want to completely replace superclass behaviour, and at other times augment it - ie call your own code before and/or after a superclass call.有时你想完全替换超类行为,而在其他时候增加它——即在超类调用之前和/或之后调用你自己的代码。

Update: The same basic logic applies to any method call.更新:相同的基本逻辑适用于任何方法调用。 Constructors sometimes need special consideration (as they often set up state which determines behaviour) and destructors because they parallel constructors (eg in the allocation of resources, eg database connections).构造函数有时需要特别考虑(因为它们经常设置决定行为的状态)和析构函数,因为它们与构造函数并行(例如在资源分配中,例如数据库连接)。 But the same might apply, say, to the render() method of a widget.但是,这同样适用于小部件的render()方法。

Further update: What's the OPP?进一步更新:什么是 OPP? Do you mean OOP?你是说面向对象? No - a subclass often needs to know something about the design of the superclass.不——子类通常需要了解超类的设计。 Not the internal implementation details - but the basic contract that the superclass has with its clients (using classes).不是内部实现细节——而是超类与其客户(使用类)的基本契约。 This does not violate OOP principles in any way.这不会以任何方式违反 OOP 原则。 That's why protected is a valid concept in OOP in general (though not, of course, in Python).这就是为什么protected通常在 OOP 中是一个有效的概念(当然在 Python 中不是)。

IMO, you should call it. IMO,你应该称呼它。 If your superclass is object , you should not, but in other cases I think it is exceptional not to call it.如果你的超类是object ,你不应该,但在其他情况下,我认为不调用它是例外的。 As already answered by others, it is very convenient if your class doesn't even have to override __init__ itself, for example when it has no (additional) internal state to initialize.正如其他人已经回答的那样,如果您的班级甚至不必重写__init__本身,那将非常方便,例如当它没有(额外的)内部状态要初始化时。

Yes, you should always call base class __init__ explicitly as a good coding practice.是的,您应该始终显式调用基类__init__作为一种良好的编码习惯。 Forgetting to do this can cause subtle issues or run time errors.忘记这样做可能会导致细微的问题或运行时错误。 This is true even if __init__ doesn't take any parameters.即使__init__不接受任何参数也是如此。 This is unlike other languages where compiler would implicitly call base class constructor for you.这与其他语言不同,在其他语言中,编译器会为您隐式调用基类构造函数。 Python doesn't do that! Python 不会那样做!

The main reason for always calling base class _init__ is that base class may typically create member variable and initialize them to defaults.总是调用基类_init__的主要原因是基类通常可以创建成员变量并将它们初始化为默认值。 So if you don't call base class init, none of that code would be executed and you would end up with base class that has no member variables.因此,如果您不调用基类 init,则不会执行任何代码,并且您最终会得到没有成员变量的基类。

Example :示例

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

This prints..这打印..

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

Run this code .运行这段代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM