---
title: "Python multiple inheritance gotcha"
url: "https://www.pardel.dev/2023/11/17/python-multiple-inheritance-gotcha"
date: 2023-11-17
author: "Paul Ardeleanu"
tags: ["Python"]
description: "Always call <code>super().__init__()</code> in the <code>__init__()</code> method of the subclass - a Python multiple inheritance gotcha."
---

# Python multiple inheritance gotcha

> TLDR; Always call `super().__init__()` in the `__init__()` method of the subclass.

I've started learning Python recently and came across a puzzling issue. I believe it's a very likely trap for newcomers so here is a quick write up.

Say we have 2 standard classes - nothing special about them - they both define a `name` property as well as a `prop_a` and `prop_b` property respectively:

```python
class A:
    def __init__(self):
        self.name = "class A"
        self.prop_a = "prop_a"

class B:
    def __init__(self):
        self.name = "class B"
        self.prop_b = "prop_b"
```

And we'll create another class `C` that inherits from both and we'll instantiate an object with it:

```python
class C(A, B):
    def __init__(self):
        super().__init__()
        self.prop_c = "prop_c"

c = C()
```

As you can expect, the name property is "taken" from the first parent class, `A` so `c.name` will return class `A`. And it should also inherit both `prop_a` and `prop_b`, right?! Well, not quite. Let's see what happens when we try to access them:

```python
print(c.name)   # prints "class A"
print(c.prop_a) # prints "prop_a"
print(c.prop_b) # returns an AttributeError (see below)
```

```shell
Traceback (most recent call last):
  File "/Users/paul/.../multi-inheritance-gotcha.py", line 19, in
    print(c.prop_b) # prop_b
          ^^^^^^^^
AttributeError: 'C' object has no attribute 'prop_b'. Did you mean: 'prop_a'?
```

HA! Same thing happens with `prop_a` if we change the order of the multiple inheritance to `class C(B, A)`. So what's going on here? Why does it work for `prop_a` but not for `prop_b`? Looks like the second parent class is not being inherited at all.

## The Dirty Fix

We can fix it by calling the `__init__()` method of the second parent class in the `C` class:

```python
class C(A, B):
    def __init__(self):
        super().__init__()
        B.__init__(self)
        self.prop_c = "prop_c"
```

In fact we can do the same for both parent classes (no need for `super().__init__()`):

```python
class C(A, B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)
        self.prop_c = "prop_c"
```

## The Real Fix

Turns out that the behavior is caused by not calling `super().__init__()` in the `__init__()` method of the parent classes. So if we add it to both `A` and `B` classes, the problem is solved:

```python
class A:
    def __init__(self):
        super().__init__()
        self.name = "class A"
        self.prop_a = "prop_a"

class B:
    def __init__(self):
        super().__init__()
        self.name = "class B"
        self.prop_b = "prop_b"
```

I still don't understand how it works internally, but it must be something to do with the way Python handles multiple inheritance internally.

## The Lesson

All classes in Python ultimately inherit from a base class called `object`. So when we create a class like `A`, it's actually inheriting from `object`.

But nobody tells you that you should call `super().__init__()` in the `__init__()` method of all of your classes. Lesson learnt! :D

Happy coding!
