Learn by reading through in order

Multiple Inheritance and MRO — Inheriting from More Than One Parent

Learn Python multiple inheritance. Combine parents with class Child(A, B):, see how the method resolution order (MRO) picks among same-named methods, and check the order with __mro__.

Last time we covered single inheritance, overriding, and super(). Python lets you inherit from more than one parent at the same time — that's multiple inheritance. This time we'll cover the syntax and the rule that decides which parent gets called when several have the same method name: the method resolution order (MRO).

The Basic Syntax

The syntax is simple — list the parent classes comma-separated. Writing class Duck(Animal, Swimmer, Flyer): means Duck inherits attributes and methods from all of Animal, Swimmer, and Flyer.

In the example below, Animal carries the name and the speak behavior, Swimmer adds swimming, Flyer adds flying — and Duck bundles all three into one capable creature.

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        pass


class Swimmer:
    def swim(self):
        return f"{self.name} is swimming"


class Flyer:
    def fly(self):
        return f"{self.name} is flying"


class Duck(Animal, Swimmer, Flyer):    # multiple inheritance
    def speak(self):
        return f"{self.name} says quack"


duck = Duck("Donald")
print(duck.speak())   # Donald says quack
print(duck.swim())    # Donald is swimming
print(duck.fly())     # Donald is flying
Duck Inherits from Three Parents
Animalname / speakSwimmerswimFlyerflyDuckspeak (override)inheritsinheritsinherits
Duck inherits attributes and __init__ from Animal, swim from Swimmer, and fly from Flyer. Only speak is overridden by Duck itself.

Build the Duck that bundles three parents.

① Define class Animal: with __init__(self, name) that assigns self.name = name.

② Inside class Swimmer:, define swim(self) returning f"{self.name} is swimming". Do the same for Flyer with fly(self).

③ Define class Duck(Animal, Swimmer, Flyer): with speak(self) returning f"{self.name} says quack".

④ Build duck = Duck("Donald") and print the return values of speak(), swim(), and fly().

(Once it runs correctly, the explanation will appear.)

Python Editor

Run code to see output

Method Resolution Order (MRO) — Which Parent Wins?

Things get tricky when multiple parents have a method with the same name. If both Swimmer and Flyer defined a move method, which one runs when you call move on a Duck instance?

Python uses the method resolution order (MRO) — a fixed lookup order — to walk the classes from top to bottom and run the first match. For multiple inheritance, the order is left to right as written in class Duck(A, B, C):. So A's same-named method wins; if it's not there, B is tried, then C.

class Swimmer:
    def move(self):
        return "swimming"

class Flyer:
    def move(self):
        return "flying"

class Duck(Swimmer, Flyer):    # left wins = Swimmer.move
    pass

class Goose(Flyer, Swimmer):   # flip the order = different result
    pass

print(Duck().move())   # swimming
print(Goose().move())  # flying
MRO Walks (A, B, C) Left to Right
Duck().move()move onDuck?no→ nextyes→ runmove onSwimmer?yes→ run
For Duck(Swimmer, Flyer), Python looks Swimmer first, then Flyer. If both define move, Swimmer's move wins. Reorder the parents and the result flips.

On CPython you can read the actual lookup order from ClassName.__mro__ (the runtime here is MicroPython, which doesn't expose the __mro__ attribute, so the snippet below is just a reference for what you'd see in regular Python).

# What CPython would show
class Swimmer:
    pass
class Flyer:
    pass
class Duck(Swimmer, Flyer):
    pass

for cls in Duck.__mro__:
    print(cls.__name__)
# Duck
# Swimmer
# Flyer
# object

What's That object at the End?

Every class in Python ultimately inherits from the built-in class object. Even when you don't write it, class Foo: is internally class Foo(object):. That's why __mro__ always ends with object.

Confirm with a quick experiment that the order you list the parents in changes the result.

① Inside class Swimmer:, define move(self) returning "swimming". Do the same for Flyer with "flying".

② Define class Duck(Swimmer, Flyer): and class Goose(Flyer, Swimmer):, both with just pass.

print the result of Duck().move() and Goose().move() — see how flipping the parent order flips the result.

Python Editor

Run code to see output

Diamond Inheritance and C3 Linearization

Another shape that comes up is diamond inheritance: B and C each inherit from A, and D inherits from both B and C — drawing the inheritance graph yields a literal diamond shape.

The Shape of Diamond Inheritance
A(common parent)Binherits ACinherits ADinherits B and Cinheritsinheritsinheritsinherits
A is the common ancestor. B and C each inherit from A. D then inherits from both B and C — the arrows form a diamond.

Python computes the MRO with an algorithm called C3 linearization, which produces the smart ordering "try the descendants (B, C) first, then walk up to the common ancestor (A) last."

class A:
    def method(self):
        return "A"

class B(A):
    def method(self):
        return "B"

class C(A):
    def method(self):
        return "C"

class D(B, C):       # diamond
    pass

print(D().method())  # B

In this example D().method() returns "B" because the MRO is D → B → C → A. If B didn't define method, C's would run; without that, A's would. "Left first, but the common ancestor is last" — that's the cheat sheet for diamond inheritance.

Calling a Specific Parent's Method by Class Name

When you specifically want to call a particular parent's method — not just whichever one wins MRO — super() only gives you the next class in the MRO, so you can call at most one parent's version. Instead, use ParentClass.method(self, ...) to pick exactly the one you want.

Since the call goes through the class side, you have to pass self yourself as the first argument — the only quirk worth remembering.

super() vs Calling by Class Name
C().hello()super().hello()MRO order(only one)A.hello(self)B.hello(self)both A and Bare callable
super() runs just one method (the next in MRO). Calling by class name like A.hello(self) lets you target a specific parent regardless of MRO — handy when you want to invoke several parent methods in sequence.
class A:
    def hello(self):
        print("hello from A")

class B:
    def hello(self):
        print("hello from B")

class C(A, B):
    def hello(self):
        A.hello(self)        # explicitly call A's hello
        B.hello(self)        # explicitly call B's hello
        print("hello from C")

C().hello()
# hello from A
# hello from B
# hello from C

Write a C class that calls both parents' hello by name.

① Define class A: with hello(self) running print("hello from A").

② Define class B: with hello(self) running print("hello from B").

③ Define class C(A, B): with hello(self) calling A.hello(self)B.hello(self)print("hello from C") in that order (don't forget to pass self).

④ Run C().hello() and confirm three lines are printed.

Python Editor

Run code to see output

Powerful, But Use It Sparingly

Multiple inheritance is convenient, but you have to keep the MRO in your head at all times to follow the behavior — that's a real cognitive cost. In practice, instead of forcing multiple inheritance, using a single parent and holding small feature classes as attributes (composition) is often clearer. Save multiple inheritance for cases like mixing in independent capabilities like Swimmer / Flyer.

What you wantHow to write it
Inherit multiple parentsclass Child(A, B): ...
See which parent winsClassName.__mro__ (CPython)
Call only the next in MROsuper().method(...)
Target a specific parentParentClass.method(self, ...)
QUIZ

Knowledge Check

Answer each question one by one.

Q1In class Duck(Swimmer, Flyer):, if both parents define a move method, which one wins?

Q2Which is the right way to read the method resolution order (MRO) of a class? (CPython)

Q3In multiple inheritance, what's the right way to call a specific parent's method by name?