Reputation: 1068
I wonder how is class C
being executed in this code flow
When none of the flow calls it.
class A:
def fun1(self):
print("This is class A")
class B(A):
def fun2(self):
super().fun1()
print("This is class B")
class C(A):
def fun1(self):
super().fun1()
print("This is class C")
class D(B, C):
def fun1(self):
self.fun2()
print("This is class D")
obj = D()
obj.fun1()
"""
# Result of this code is
This is class A
This is class C
This is class B
This is class D
"""
Upvotes: 4
Views: 154
Reputation: 362746
The method resolution order used is a C3 linearization algorithm, and super
itself uses this MRO. The resolution for a type is obtained with the mro()
method, and cached in the __mro__
attribute:
>>> D.__mro__
(__main__.D, __main__.B, __main__.C, __main__.A, object)
>>> D.mro()
[__main__.D, __main__.B, __main__.C, __main__.A, object]
Since you call print after calling super, you'll see the reverse of this, i.e. A -> C -> B -> D.
I wonder how is class C being executed in this code flow when none of the flow calls it.
D.fun2
doesn't exist, so obj.fun2()
gets resolved (via the MRO) on B
instead:
>>> obj = D()
>>> obj.fun2
<bound method B.fun2 of <__main__.D object at 0x7fffe89a3cd0>>
Then in B.fun2
, the C.fun1
gets called here:
class B(A):
def fun2(self):
super().fun1() # <-- this resolves to C.fun1, not A.fun1!
print("This is class B")
C.fun1
is called since it's D's MRO which is active here, not B's, because the type(self) is D
. The built-in function super
is perhaps confusingly named, since the proxy object it returns does not always resolve attributes on a parent class, they may be resolved on a sibling class like in your example. Python's implementation was more or less lifted from another programming language called Dylan, where the equivalent of super
had a less confusing name: next-method
.
Upvotes: 5