PY

Python Fundamentals

18 lessons

Progress0%
1. Introduction to Python
1What is Python?2Setting Up Python
2. Variables and Data Types
1Variables in Python2Data Types
3. Control Flow
Conditional StatementsLoops
4. Functions
Function Basics
5. Data Structures
Lists Deep DiveTuples & SetsDictionaries & Comprehensions
6. Advanced Functions
Closures & Higher-Order FunctionsDecorators & Lambda
7. Object-Oriented Python
Classes & InstancesInheritance & Dunder Methods
8. Exception Handling
try / except / finallyCustom Exceptions & Context Managers
9. Modules & File I/O
Modules & PackagesFile I/O & JSON
All Tutorials
PythonObject-Oriented Python
Lesson 14 of 18 min
Chapter 7 · Lesson 2

Inheritance & Dunder Methods

Inheritance & Dunder Methods

Inheritance

Inheritance lets a subclass reuse and specialise the behaviour of a base class:

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

    def speak(self):
        raise NotImplementedError

class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

super()

super() delegates a method call to the parent class, making it easy to extend without fully replacing the parent's logic:

python
class ElectricCar(Car):
    def __init__(self, make, model, battery_kwh):
        super().__init__(make, model)   # call Car.__init__
        self.battery_kwh = battery_kwh

Multiple Inheritance & MRO

Python allows a class to inherit from multiple bases. The Method Resolution Order (MRO) determines which method is used when the same name exists in multiple bases. Python uses the C3 linearisation algorithm:

python
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

Use ClassName.__mro__ or help(ClassName) to inspect the MRO.

Dunder (Magic) Methods

Dunder methods let your objects integrate with Python's operators and built-in functions:

DunderTriggered by
__len__(self)len(obj)
__eq__(self, other)obj == other
__lt__(self, other)obj < other
__add__(self, other)obj + other
__contains__(self, item)item in obj
__iter__(self)for x in obj
__getitem__(self, key)obj[key]

dataclasses

The @dataclass decorator (Python 3.7+) auto-generates __init__, __repr__, and __eq__ based on annotated fields:

python
from dataclasses import dataclass, field

@dataclass(order=True)
class Point:
    x: float
    y: float
    label: str = ""        # field with default
    tags: list = field(default_factory=list)  # mutable default

With order=True, comparison operators (<, >, etc.) are generated automatically. Use frozen=True for an immutable dataclass.

Code Examples

Inheritance & super()python
class Vehicle:
    def __init__(self, make, model, year):
        self.make  = make
        self.model = model
        self.year  = year

    def describe(self):
        return f"{self.year} {self.make} {self.model}"

class Car(Vehicle):
    def __init__(self, make, model, year, doors=4):
        super().__init__(make, model, year)
        self.doors = doors

    def describe(self):
        base = super().describe()
        return f"{base} ({self.doors}-door)"

class ElectricCar(Car):
    def __init__(self, make, model, year, battery_kwh):
        super().__init__(make, model, year)
        self.battery_kwh = battery_kwh

    def describe(self):
        base = super().describe()
        return f"{base} [Electric, {self.battery_kwh} kWh]"

v  = Vehicle("Generic", "Truck", 2020)
c  = Car("Toyota", "Camry", 2022)
ev = ElectricCar("Tesla", "Model 3", 2024, 82)

print(v.describe())
print(c.describe())
print(ev.describe())
print("Is Car?", isinstance(ev, Car))
print("Is Vehicle?", isinstance(ev, Vehicle))

Each subclass calls super().__init__() to initialise the parent's attributes. Overriding describe() and calling super().describe() extends rather than replaces the parent's behaviour. isinstance() checks the full inheritance chain.

Dunder Methodspython
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __len__(self):
        return 2  # always 2 dimensions

    def __abs__(self):
        return (self.x**2 + self.y**2) ** 0.5

v1 = Vector(1, 2)
v2 = Vector(3, 4)

print(v1 + v2)
print(v1 * 3)
print(v1 == Vector(1, 2))
print(len(v1))
print(f"|v2| = {abs(v2):.2f}")

Implementing __add__ enables the + operator; __mul__ enables *; __eq__ enables ==; __abs__ enables abs(). Python maps operators to their corresponding dunder methods, giving your objects seamless integration with built-in syntax.

dataclassespython
from dataclasses import dataclass, field

@dataclass(order=True)
class Student:
    name:    str
    grade:   float
    courses: list = field(default_factory=list)

    def enroll(self, course):
        self.courses.append(course)
        return self

    def __str__(self):
        return f"{self.name} (GPA: {self.grade:.1f}) — {', '.join(self.courses) or 'no courses'}"

s1 = Student("Alice", 3.8)
s2 = Student("Bob",   3.5)
s3 = Student("Carol", 3.9)

s1.enroll("Math").enroll("Physics")
s2.enroll("History")

print(s1)
print(s2)

# order=True enables comparison operators
students = [s3, s1, s2]
students.sort()            # sorts by name (first field)
for s in students:
    print(s.name, s.grade)

@dataclass auto-generates __init__ and __repr__. order=True generates __lt__, __le__, __gt__, __ge__ based on the fields in order. field(default_factory=list) avoids the mutable-default-argument trap — each instance gets its own fresh list.

Quick Quiz

1. What does super().__init__() do inside a subclass __init__?

2. Which dunder method is called when you use the + operator on two objects?

3. What does the @dataclass decorator automatically generate?

Was this lesson helpful?

PreviousNext