• Martin Thoma
  • Home
  • Categories
  • Tags
  • Archives
  • Support me

Pythons super() function

Contents

  • Single Inheritance
  • Multiple Inheritance
  • Multiple Inheritance: Linearization
  • See also

Python has a built-in function called super(). It might behave different from what you thought.

Single Inheritance

As a first simple example, consider this script:

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


class B(A):
    def __init__(self):
        print("B")
        super().__init__()


class C(B):
    def __init__(self):
        print("C")
        super().__init__()


C()

This prints:

C
B
A

This is simple, because every class inherits from exactly one other class and the inheritance tree looks like this:

Inheritance tree where A is the parent of B and B is the parent of C.
Inheritance tree where A is the parent of B and B is the parent of C.

Multiple Inheritance

Python supports multiple inheritance. This means classes can inherit from arbitrary many classes.

Let's start with a simple example how super works here:

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


class B1(A):
    def __init__(self):
        print("B1")
        super().__init__()


class B2(A):
    def __init__(self):
        print("B2")
        super().__init__()


class C(B1, B2):
    def __init__(self):
        print("C")
        super().__init__()


C()

The inheritance tree looks like this:

Inharitance Tree where A is the parent of B1 and B2. They are the parents of C.
Inharitance Tree where A is the parent of B1 and B2. They are the parents of C.

The output of this script is:

C
B1
B2
A

Still expected, right? Basically going deeper and left to right.

Multiple Inheritance: Linearization

Where the mental model might break is with the following example. The inheritance tree is still the same. However, within B1 I don't call super anymore. Which output would you expect?

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


class B1(A):
    def __init__(self):
        print("B1")


class B2(A):
    def __init__(self):
        print("B2")
        super().__init__()


class C(B1, B2):
    def __init__(self):
        print("C")
        super().__init__()


C()

The received output is

C
B1

Now, why does it not print B2 and not A? After all, C still inherits from B2 and B2 still calls super which would point to A, right?

The reason is that the method resolution order is:

>>> print(C.__mro__)
(<class '__main__.C'>, <class '__main__.B1'>, <class '__main__.B2'>, <class '__main__.A'>, <class 'object'>)

This means that super searches first in B1, then B2, then A and then object for the __init__ function. If it is found in one of them, it just executes that one. It does not continue searching.

Super is a call-next-method. It calls the next method in the method resolution order. And it is cooperative: If one in the line does not call super, then the line ends.

See also

  • StackOverflow:
    • Callisto: How does Python's super() work with multiple inheritance?, 2010.
    • Mizipzor: Understanding Python super() with init() methods, 2009.
  • Raymond Hettinger: Super considered super! at PyCon on YouTube, 2015.
  • Raymond Hettinger: Python’s super() considered super!, 2011.

Published

Jun 11, 2020
by Martin Thoma

Category

Code

Tags

  • Inheritance 1
  • Python 141

Contact

  • Martin Thoma - A blog about Code, the Web and Cyberculture
  • E-mail subscription
  • RSS-Feed
  • Privacy/Datenschutzerklärung
  • Impressum
  • Powered by Pelican. Theme: Elegant by Talha Mansoor