I'm trying to understand how multiple inheritance (i.e., the C3 algorithm for method resolution order) works in Python. The toy example with the classical diamond dependency below gives me results that are against my intuition.
In particular, I noticed the following:
- When run as-is (i.e., both
AandAAhavesupercalls toBase, then the output is:<B> <A> <AA> <Base> </Base> </AA> </A> </B>. - When only the the line marked
(1)is commented out (i.e., no call toBaseconstructor inA), then the output is<B> <A> </A> </B>. - When only the the line marked
(2)is commented out (i.e., no call toBaseconstructor inAA), then the output is<B> <A> <AA> </AA> </A> </B>. - When both lines marked
(1)and(2)are commented out, then the output is<B> <A> </A> </B>.
My questions are:
- In case 1, it seems that execution is interrupted in the constructor of
Abefore the explicit call to theBaseconstructor, jumps to ("recurses into") theAAconstructor (as ifAAwould derive fromA), then descends intoBase, and then back out. Is this what happens? (I understand the MROB->A->AA->Basecomes from the C3 requirement that child classes be called before parent classes.) - In case 2, why is the constructor of
AAnever called, although in case 3 it is called? - In both cases 2 and 3, why is the
Baseconstructor not called, despite an explicit call in the constructor ofAA(case 2) /A(case 3)? (In example 1 it is called as I would expect.)
Here are the MROs of the classes:
- Class
B:(<class '__main__.B'>, <class '__main__.A'>, <class '__main__.AA'>, <class '__main__.Base'>, <type 'object'>) - Class
A:(<class '__main__.A'>, <class '__main__.Base'>, <type 'object'>) - Class
AA:(<class '__main__.AA'>, <class '__main__.Base'>, <type 'object'>) - Class
Base:(<class '__main__.Base'>, <type 'object'>)
Code:
#!/usr/bin/env python # Using Python 2.7 class Base(object): def __init__(self): print '<Base>', super(Base, self).__init__() print '</Base>', class A(Base): def __init__(self): print '<A>', super(A, self).__init__() # (1) print '</A>', class AA(Base): def __init__(self): print '<AA>', super(AA, self).__init__() # (2) print '</AA>', class B(A, AA): def __init__(self): print '<B>', super(B, self).__init__() print '</B>', if __name__ == '__main__': obj = B()