英文:
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__
,那么first
和last
属性将永远不会被定义,并且实例将保持不正确地初始化。至于决定不自动调用父级__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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论