英文:
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!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论