Understanding Python's super() with Multiple Inheritance and Method Resolution Order

Nov 09, 2025 · Programming · 359 views · 7.8

Keywords: Python | super() | multiple inheritance | method resolution order | MRO | cooperative inheritance

Abstract: This technical article provides a comprehensive analysis of Python's super() function in multiple inheritance scenarios, focusing on the C3 linearization algorithm for Method Resolution Order (MRO). Through detailed code examples, it demonstrates how super() traverses the inheritance hierarchy, explains cooperative inheritance patterns, parameter passing strategies, and common pitfalls. The article combines official documentation with community insights to offer a complete guide for effective multiple inheritance design in Python.

Fundamentals of super() and Multiple Inheritance

In Python object-oriented programming, the super() function is a crucial mechanism for method invocation, particularly in multiple inheritance scenarios. When a class inherits from multiple parent classes, Python employs the Method Resolution Order (MRO) to determine attribute lookup priority.

Consider this basic example:

class First(object):
    def __init__(self):
        print("first")

class Second(object):
    def __init__(self):
        print("second")

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print("that's it")

When instantiating the Third class, super(Third, self).__init__() will call the First.__init__ method. This occurs because Python's MRO algorithm traverses the inheritance chain from left to right, prioritizing First as the first parent class.

C3 Linearization for Method Resolution Order

Python uses the C3 linearization algorithm to compute MRO, ensuring:

The specific resolution order can be inspected via the Class.__mro__ attribute:

>>> Third.__mro__
(<class '__main__.Third'>, <class '__main__.First'>, 
 <class '__main__.Second'>, <type 'object'>)

Cooperative Inheritance and super() Call Chains

Proper multiple inheritance design requires all relevant classes to use super() forming cooperative call chains:

class First(object):
    def __init__(self):
        super(First, self).__init__()
        print("first")

class Second(object):
    def __init__(self):
        super(Second, self).__init__()
        print("second")

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print("third")

Instantiating Third() produces the output sequence:

second
first
third

Call flow analysis:

  1. Third.__init__ calls super(), MRO points to First.__init__
  2. First.__init__ calls super(), MRO points to Second.__init__
  3. Second.__init__ calls super(), MRO points to object.__init__
  4. The call stack returns sequentially to each __init__ method, executing print statements

MRO Calculation in Complex Inheritance Structures

For complex scenarios like diamond inheritance, MRO calculation follows specific rules. Consider this hierarchy:

class First(object):
    def __init__(self):
        print("first")

class Second(First):
    def __init__(self):
        print("second")

class Third(First):
    def __init__(self):
        print("third")

class Fourth(Second, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print("that's it")

This structure's MRO is: [Fourth, Second, Third, First, object]. Python's C3 algorithm ensures each class appears only once in the MRO while maintaining logical inheritance order.

MRO Conflicts and Error Handling

When inheritance relationships cannot form a consistent MRO, Python raises an exception:

class First(object):
    def __init__(self):
        print("first")
        
class Second(First):
    def __init__(self):
        print("second")

class Third(First, Second):
    def __init__(self):
        print("third")

This definition causes:

TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution order (MRO) for bases Second, First

Conflict reason: Third inherits from both First and Second, while Second inherits from First, creating contradictory inheritance order requirements.

Parameter Passing and Cooperative Method Design

Method parameter passing in multiple inheritance requires special design. Reference this improved pattern:

class Car:
    def __init__(self, *, door, wheel, **kwargs):
        super().__init__(**kwargs)
        self.door = door
        self.wheel = wheel
    
    def start(self):
        print('Start the Car')

class Flyable:
    def __init__(self, *, wing, **kwargs):
        super().__init__(**kwargs)
        self.wing = wing
    
    def start(self):
        print('Start the Flyable object')

class FlyingCar(Flyable, Car):
    pass

# Instantiation requires all necessary parameters
car = FlyingCar(wing=1, wheel=2, door=3)
car.start()  # Output: Start the Flyable object

Key design points:

Advanced Application: Custom Base Classes and Parameter Management

For complex multiple inheritance systems, specialized base classes can manage super() calls:

class SuperObject:
    def __init__(self, **kwargs):
        mro = type(self).__mro__
        # Validate MRO structure
        assert mro[-1] is object
        if mro[-2] is not SuperObject:
            raise TypeError('Inheritance hierarchy error')
        super().__init__()
    
    def super_call(self, super_, funcname, **kwargs):
        """Cooperative method invocation utility"""
        super_func = getattr(super_, funcname, None)
        if super_func is not None:
            return super_func(**kwargs)

class A(SuperObject):
    def __init__(self, **kwargs):
        print("A")
        super(A, self).__init__(**kwargs)

class B(SuperObject):
    def __init__(self, **kwargs):
        print("B")
        super(B, self).__init__(**kwargs)

class C(A, B):
    def __init__(self, **kwargs):
        print("C")
        super(C, self).__init__(**kwargs)

This design pattern ensures:

Best Practices Summary

Based on Python community experience, using super() in multiple inheritance should follow:

  1. Consistency Principle: All classes in the inheritance hierarchy should either use super() or none should
  2. Parameter Design: Methods should use **kwargs to receive additional parameters, ensuring parameter chain畅通
  3. MRO Verification: Use Class.__mro__ to verify resolution order before complex inheritance structures
  4. Avoid Diamond Inheritance: Minimize complex multiple inheritance, prefer composition or mixin patterns
  5. Documentation: Public inheritance hierarchies should clearly document expected MRO behavior

By understanding MRO mechanisms and correctly using super(), developers can build robust multiple inheritance systems, fully leveraging Python's powerful object-oriented programming capabilities.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.