为什么在初始化新属性时需要调用父类的__init__方法?

huangapple go评论63阅读模式
英文:

why do i need to call the __init__ method of a parent class when initializing new atrributes?

问题

新手程序员,我在想为什么我需要在子类中调用父类的__init__方法,如果我没有触及第一个__init__方法中的任何参数。方法解析顺序的整个重点不就是,如果子类中不存在某个方法,那么父类将在方法解析顺序中在子类后被调用吗?

例如,如果我有一个带有名和姓参数的类的实例。但是在子类中,我添加了一个邮箱,然后决定只为邮箱编写一个__init__方法,并打印名。Python不应该在检查子类后再检查父类,看看是否在那里的__init__方法中有“名”属性,而不是给我AttributeError吗?

英文:

New programmer here, and I'm just wondering why I need to call the __init__ method of a parent class in my subclass, if I'm not touching any of the arguments in the first __init__ method. Isn't the whole point of Method Resolution Order, that the parent class will be called after the subclass in the Method Resolution Order, if a certain method isn't in the subclass.

fx. If I have an instance of a class with the first and last name arguments. but then in a subclass I add an email, and decide to just write an __init__ method for the email, and then print the first name. shouldn't Python after checking the subclass then check the parent class to see if the "first name" attribute is in an __init__ method there, instead of giving me an AttributeError.

答案1

得分: 3

方法解析操作符仅与属性查找相关。

class Person:
    def __init__(self, *, first, last, **kwargs):
        super().__init__(**kwargs)
        self.first = first
        self.last = last


class PersonWithEmail:
    def __init__(self, *, email, **kwargs):
        super().__init__(**kwargs)
        self.email = email


p = Person(first="John", last="Doe", email="jdoe@example.com")

当我们调用Person时,我们到达需要调用Person.__init__的时刻。因为Person.__init__被定义了,我们调用它,一旦它返回,我们就完成了。只有当Person.__init__ 没有 被定义时,MRO才会起作用,以找到Person的祖先中定义了我们可以使用的__init__方法。

Person.__init__内部,我们只是调用找到的代码。不会隐式调用任何继承的__init__方法。super().__init__找到MRO中下一个具有定义的__init__方法的类并调用它。只有当MRO中的所有类在重写方法中使用super时,我们才合作确保最终调用每个适当的方法。

如果PersonWithEmail没有调用super().__init__,那么firstlast属性将永远不会被定义,并且实例将保持不正确地初始化。至于决定不自动调用父级__init__是否是一个好决定,这是你可以讨论的问题。不过,我会指出,这样做会使__init__在某种程度上变得特殊,而它本来不是。它就像任何其他方法一样,如果你真的想这样做,你可以选择完全覆盖父类的__init__。此外,Python的类系统与其早期有了一些演变,以前你可能会这样做的事情现在可能不是你想要做的事情,但是改变关于不隐式调用父类的规则将是一种破坏兼容性的改变,而这从未被认为是必要的。

英文:

The method resolution operator is only relevant to attribute lookup.

class Person:
    def __init__(self, *, first, last, **kwargs):
        super().__init__(**kwargs)
        self.first = first
        self.last = last


class PersonWithEmail:
    def __init__(self, *, email, **kwargs):
        super().__init__(**kwargs)
        self.email = email


p = Person(first="John", last="Doe", email="jdoe@example.com")

When we call Person, we reach a point where we need to call Person.__init__. Since Person.__init__ is defined, we call it, and once it returns, we're done. Only if Person.__init__ is not defined does the MRO come into play, to find an ancestor of Person that does define an __init__ method that we can use.

Inside Person.__init__, we just call the code that's found. No implicit call to any inherited __init__ method is made. super().__init__ finds the next class in the MRO with an __init__ method defined and calls it. Only when all classes in the MRO are using super in overriden methods do we cooperatively ensure that each appropriate method gets called eventually.

If PersonWithEmail does not call super().__init__, then the first and last attribute never get defined, and the instance remains incorrectly initialized. As to whether the decision to not call a parent __init__ automatically was a good one, that's something you can debate. I will, however, point out that doing so would make __init__ special in a way that it otherwise is not. It's a method like any other, and you can choose to completely override a parent's __init__ if you really want to. Also, Python's class system has evolved slightly from its early days, and things you might have done back then aren't things you would want to do now, but changing the rule about no implicit parent calls would be a compatibility-breaking change that was never deemed necessary.

huangapple
  • 本文由 发表于 2023年2月7日 04:28:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75366241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定