Multiple inheritance and a broken super() chain

Peter Slížik peter.slizik at gmail.com
Mon Jul 3 13:38:08 EDT 2023


Hello.

The legacy code I'm working with uses a classic diamond inheritance. Let me
call the classes *Top*, *Left*, *Right*, and *Bottom*.
This is a trivial textbook example. The classes were written in the
pre-super() era, so all of them initialized their parents and Bottom
initialized both Left and Right in this order.

The result was expected: *Top* was initialized twice:

Top.__init__() Left.__init__() Top.__init__() Right.__init__()
Bottom.__init__()

Now I replaced all parent init calls with *super()*. After this, Top was
initialized only once.

Top.__init__() Right.__init__() Left.__init__() Bottom.__init__()

But at this point, I freaked out. The code is complex and I don't have the
time to examine its inner workings. And before, everything worked correctly
even though Top was initialized twice. So I decided to break the superclass
chain and use super() only in classes inheriting from a single parent. My
intent was to keep the original behavior but use super() where possible to
make the code more readable.

class Top:
def __init__(self):
print("Top.__init__()")

class Left(Top):
def __init__(self):
super().__init__()
print("Left.__init__()")

class Right(Top):
def __init__(self):
super().__init__()
print("Right.__init__()")

class Bottom(Left, Right):
def __init__(self):
Left.__init__(self) # Here I'm calling both parents manually
Right.__init__(self)
print("Bottom.__init__()")

b = Bottom()


The result has surprised me:

Top.__init__() Right.__init__() Left.__init__() Top.__init__()
Right.__init__() Bottom.__init__()

Now, as I see it, from the super()'s point of view, there are two
inheritance chains, one starting at Left and the other at Right. But
*Right.__init__()* is called twice. What's going on here?

Thanks,
Peter


More information about the Python-list mailing list