Legends ofPythos
Claim your name
Objects and Classes

Multiple inheritance and private names

Lesson 10 of 13

Watch the lesson1:09 ยท with Torsten
So far you have seen a class inherit from one parent. Python lets it do more: class FlyingCar(Car, Plane) makes FlyingCar pull methods from both parents.

Method resolution order

When two parents have the same method name, Python picks one by following a fixed rule called the MRO. It checks the class itself first, then walks through the parent list from left to right. You can see this exact order with ClassName.__mro__ or ClassName.mro().
class Car:
    def move(self):
        return 'drives'

class Plane:
    def move(self):
        return 'flies'

class FlyingCar(Car, Plane):
    pass

print(FlyingCar().move())                          # drives: Car is listed first
print([k.__name__ for k in FlyingCar.__mro__])     # ['FlyingCar', 'Car', 'Plane', 'object']
FlyingCar, then Car, then Plane: left to right through the parents

Mixins and super()

Small helper classes that each add one behaviour are called mixins. A common pattern is a JsonMixin with just a to_json() method, combined with your main parent. Because Python walks the MRO to find methods and call super(), every class in a cooperative chain should accept flexible arguments โ€” usually **kwargs โ€” so each one can pass anything it does not need straight through.
class JsonMixin:
    def to_json(self):
        return f'{{"name": "{self.name}"}}'

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

class Truck(JsonMixin, Vehicle):    # one mixin plus the main parent
    pass

t = Truck('Hauler')
print(t.to_json())   # {"name": "Hauler"}
A mixin adds one method without owning state

Name mangling: double underscore names

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance

class Sneaky(BankAccount):
    def __init__(self, balance):
        super().__init__(balance)
        self.__balance = 0          # stored as _Sneaky__balance: no clash

s = Sneaky(100)
print(s._BankAccount__balance)  # 100: the parent's value is untouched
print(s._Sneaky__balance)       # 0
# print(s.__balance)            # AttributeError: no attribute called __balance
self.__x inside a class becomes _ClassName__x
Writing self.__balance tells Python to store it as _BankAccount__balance. A subclass that accidentally writes the same name gets its own mangled slot, so nothing is silently overwritten. It is a guard against collisions โ€” not real privacy, because anyone can still reach the mangled name. For everyday code you will usually prefer the single-underscore convention from an earlier lesson.

Your turn

0 of 3 solved

Exercise 1

+40 XP
Write a class Car with a method move() returning 'drives', and a class Plane whose move() returns 'flies'. Then write class FlyingCar(Car, Plane) and class CarPlane(Plane, Car), each with just pass as its body. Finally store [c.__name__ for c in FlyingCar.__mro__] in order.
class Car:
    pass




class Plane:
    pass




# FlyingCar(Car, Plane) and CarPlane(Plane, Car)


order = []

Run your code to check it against the tests.

Exercise 2

+40 XP
A mixin adds one behaviour to any class. Write JsonMixin with a method to_json() that returns json.dumps(self.__dict__, sort_keys=True). Write a plain class Item whose __init__(self, name, price) stores both. Then combine them: class Product(JsonMixin, Item) with just pass, and class Customer(JsonMixin) whose __init__(self, name, email) stores both. For example, Product('axe', 12).to_json() is '{"name": "axe", "price": 12}'.
import json




class JsonMixin:
    pass




class Item:
    pass




# Product and Customer go here

Run your code to check it against the tests.

Exercise 3

+40 XP
Write a class Account that keeps its money in self.__balance (two underscores), with deposit(amount) adding to it and balance() returning it. Then write Savings(Account), whose __init__ calls super().__init__(balance) and then sets its own self.__balance = 0 for its own records. Name mangling stores the two as _Account__balance and _Savings__balance, so the subclass cannot clobber the account's money.
class Account:
    def __init__(self, balance):
        pass


    # deposit and balance go here




class Savings(Account):
    def __init__(self, balance):
        pass

Run your code to check it against the tests.