super
works with the method resolution order (MRO) of the class. The MRO always contains at least two classes: the class itself, and object
(because all classes implicitly inherit from object
)
>>> class ABC: pass
...
>>> ABC.__mro__
(<class '__main__.ABC'>, <class 'object'>)
If there are any explicitly named base classes in the class
statement, those and their base classes will appear in the MRO somewhere between the new class and object
.
>>> class ABC(str): pass
...
>>> ABC.__mro__
(<class '__main__.ABC'>, <class 'str'>, <class 'object'>)
Regarding your question "why super
?", consider this standard example:
class A:
def foo(self):
print("A")
class B(A):
def foo(self):
super().foo()
print("B")
class C(A):
def foo(self):
super().foo()
print("C")
class D(B, C):
def foo(self):
super().foo()
print("D")
The MRO for D
is (D, B, C, A)
. Notice the call super().foo
in B.foo
. Looking only at the class B
, you might assume that super().foo()
is a call to A.foo
. But when self
is an instance of D
(as is the case with D().foo()
, for example), then super
refers to C
, not A
, because C
comes immediately after B
in the MRO.
>>> D().foo()
A
C
B
D
foo
outputs the classes in the MRO (sans object
; A
doesn't use super
because A
"introduced" foo
into the hierarchy) in reverse order, from least to most specific.