英文:
Super()__init__ on multiple parent classes for Python
问题
这是因为在多重继承中,Python 使用 C3 线性化算法来确定方法解析顺序(Method Resolution Order,MRO)。尽管在类定义中 Derived 继承顺序是 Base1, Base2,但 MRO 实际上是根据 C3 算法确定的,以确保在多重继承情况下方法解析的一致性。
因此,当你创建 Derived 的实例时,它会按照 MRO 的顺序来调用构造函数。在这种情况下,MRO 是 Base1, Base2,所以首先调用的是 Base2 的 __init__
方法,然后才是 Base1 的 __init__
方法,这就是为什么你看到输出中先打印了 "Base2 init"。
这个行为是 Python 多重继承的一部分,它确保了方法解析的一致性和可预测性。
英文:
class Base1:
def __init__(self):
super().__init__()
print("Base1 __init__")
class Base2:
def __init__(self):
print("Base2 __init__")
class Derived(Base1, Base2):
pass
# Create an instance of the Derived class
d = Derived()
This outputs:
Base2 __init__
Base1 __init__
What principle or mechanism makes it print Base2 __init__
?
Isn't MRO on Derived supposed to be Base1->Base2, and thus only Base1's init should be run?
答案1
得分: 4
这与一直以来的原理相同,super
获取方法解析顺序中的下一个方法。
现在,这是Derived
的方法解析顺序(mro):
>>> Derived.mro()
[<class '__main__.Derived'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>]
因此,在Derived
上解析__init__
时,首先检查是否存在Derived.__init__
。它不存在,然后检查Base1.__init__
,并找到它,然后调用它。
在Base1.__init__
内,您调用super().__init__()
。现在,理解这一点至关重要,隐式参数是super(Base1, self)
。因此,由于此处的self
是Derived
的一个实例,将会查看Derived
的方法解析顺序。然后super
决定获取传递给它的类之后方法解析顺序中的下一个类。所以:
[<class '__main__.Derived'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>]
^^^ ^^^
我们在这里 所以我们选择这个类
在Base1
之后方法解析顺序中的下一个类是Base2
,因此它调用Base2.__init__
。
这就是它应该工作的方式。这就是super
的美妙之处!
英文:
It's the same principle as always, super
gets the next method in the method resolution order.
Now, here is the mro of Derived
:
>>> Derived.mro()
[<class '__main__.Derived'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>]
So when __init__
is resolved on Derived
, it first checks if Derived.__init__
exists. It doesn't, so then it checks Base1.__init__
, and finds it, and it is called.
Inside Base1.__init__
, you call super().__init__()
. Now this is crucial to understand, the implicit arguments are super(Base1, self)
. So, since self
here is an instance of Derived
, the mro of Derived
is consulted. And then super decides to take the next class in the MRO after the class that was passed to super. So:
[<class '__main__.Derived'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>]
^^^ ^^^
we are here so we pick this one
And the next class in the MRO after Base1
is Base2
, so it calls Base2.__init__
This is all how it's supposed to work. This is the beauty behind super!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论