0

Consider the following code:

class A(object):
    def __init__(self):
        print("A.__init__")
        super(A, self).__init__()          # 1
        print("A.__init__ finished")

class B(A):
    def __init__(self):
        print("B.__init__")
        super(B, self).__init__()          # 2
        print("B.__init__ finished")

class C(A):
    def __init__(self):
        print("C.__init__")
        super(C, self).__init__()
        print("C.__init__ finished")

class D(B, C):
    def __init__(self):
        print("D.__init__")
        print("Initializing B")
        B.__init__(self)                   # 3
        print("B initialized")
        print("Initializing C")
        C.__init__(self)                   # 4
        print("C initialized")
        print("D.__init__ finished")

D()

# D.__init__
# Initializing B
# B.__init__
# C.__init__
# A.__init__
# A.__init__ finished
# C.__init__ finished
# B.__init__ finished
# B initialized
# Initializing C
# C.__init__
# A.__init__
# A.__init__ finished
# C.__init__ finished
# C initialized
# D.__init__ finished

As far as I understand, the algorithm is as follows:

D.__init__ at (3) -> B.__init__ -> 
-> super().__init__ -> (super of self.__class__).__init__ ->
-> C.__init__ (# why C?) -> super().__init__ -> 
-> A.__init__

D.__init__ at (4) -> C.__init__ ->
-> super().__init__ -> 
-> A.__init__

Actually there are three questions:
1. Why super().__init__() call in B.__init__ (at 2) calls C.__init__ when self is an instance of D?
2. How to avoid calling C.__init__ and A.__init__ twice in this case?
2.1 What is the right way to initialize all the classes the current class inherits from?

khachik
  • 28,112
  • 9
  • 59
  • 94

1 Answers1

5

Q: Why super().__init__() call in B.__init__ (at 2) calls C.__init__ when self is an instance of D?

When you call

super(X, self).__init__

Python looks up the MRO self.__class__.mro(). It then calls __init__ from the next class in the MRO after X.

When self is an instance of D, self.__class__.mro() is [D, B, C, A]. So super(B, self).__init__() calls C.__init__(self).


Q: What is the right way to initialize all the classes the current class inherits from?

Use super in D.__init__ as well:

class D(B, C):
    def __init__(self):
        print("D.__init__")
        super(D, self).__init__()
        print("D.__init__ finished")
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 1
    I posted a simplified case. Actual classes B and C have different signature. – khachik Sep 17 '12 at 10:49
  • 4
    The is one of the [pitfalls](https://fuhm.org/super-harmful/) of using super. The signatures must all match, because you can not control which classes's method is called next by super. As a counterbalance to the pitfalls article, also read [Hettinger's take on super()](http://rhettinger.wordpress.com/2011/05/26/super-considered-super/). – unutbu Sep 17 '12 at 10:54