0

I'm confused about the way Python class inherit from multiple parent classes.

If the parent classes all inherit from the same grand-parent class, everything is wonderful.

# grand-parent class
class Z():
    def __init__(self):
        pass

# parent class A
class A(Z):
    def __init__(self):
        super().__init__()
        self.x = 1

# parent class B
class B(Z):
    def __init__(self):
        super().__init__()
        self.y = 2

# parent class C
class C(Z):
    def __init__(self):
        super().__init__()
        self.z = 3

# target class D
class D(A, B, C):
    def __init__(self):
        super().__init__()

d = D()
print(vars(d))
#{'x': 1, 'y': 2, 'z': 3}

Without the same grand-parent class, only variables from the first parent class is inherited.

# parent class A
class A():
    def __init__(self):
        self.x = 1

# parent class B
class B():
    def __init__(self):
        self.y = 2

# parent class C
class C():
    def __init__(self):
        self.z = 3

# target class D
class D(A, B, C):
    def __init__(self):
        super().__init__()

d = D()
print(vars(d))
#{'x': 1}
Gary Liao
  • 51
  • 5
  • 1
    You haven't just removed the common ancestor, you've removed *the super calls*. Also you've mistyped `__init` in both examples. – jonrsharpe Oct 11 '19 at 07:33
  • I fixed the typo error. I don't understand the rest of your comment. – Gary Liao Oct 11 '19 at 07:39
  • 1
    What exactly don't you understand? I literally just mean you've removed the calls to super, in the parent class implementations of `__init__`. If you put those back, it will work whether or not Z is involved. – jonrsharpe Oct 11 '19 at 07:41
  • You are right, but I don't understand why. Why class A, B, C can call super().__init__() while they don't inherit from any class? – Gary Liao Oct 11 '19 at 07:44
  • 1
    They inherit from object. – jonrsharpe Oct 11 '19 at 07:46
  • Great thanks. It seems that I asked a stupid question, but I read books and search on Google for several hours, just couldn't find the right path to this simple and clear answer. should I delete this question? – Gary Liao Oct 11 '19 at 07:50
  • 1
    @jonrsharpe, Could you elaborate a bit more? I checked the mro of the class D (the second implementation in the post) and got this `>>> D.mro() [, , , , ]`. It does inherit from class A, B and C ` So why doesn't it have the attributes from these classes? Do you have any links that mandate having `super` being called in parent classes so that child classes can inherit their variables? – Clock Slave Oct 11 '19 at 07:52
  • @ClockSlave what? It *does* inherit their attributes. `__init__`, like other methods, is an attribute. However, there are multiple implementations of that method - B's is *shadowed* by A's, for example. That's why you need super. – jonrsharpe Oct 11 '19 at 08:04
  • @jonrsharpe Okay. I understand there are multiple, `__init__` implementations with that of `A` taking the highest precedence. What I am trying to understand is how does the adding of `super` to A, B, and C change the outputs that the OP has shown? – Clock Slave Oct 11 '19 at 08:13
  • @ClockSlave see e.g. https://stackoverflow.com/questions/222877/what-does-super-do-in-python – jonrsharpe Oct 11 '19 at 08:16

1 Answers1

2

Python's method resolution order works from Left to Right. It will only call the init method of the first class(A in your case). This will give you the desired result-

class A():
def __init__(self):
    super().__init__()
    self.x = 1

# parent class B
class B():
    def __init__(self):
        super().__init__()
        self.y = 2

# parent class C
class C():
    def __init__(self):
        self.z = 3

# target class D
class D(A, B, C):
    def __init__(self):
        super().__init__()

d = D()
print(vars(d))
Saurabh Sangwan
  • 339
  • 2
  • 6