foreach-ui logo
codeLanguages
account_treeDSA

Quick Actions

quizlock Random Quiz
trending_uplock Progress
  • 1
  • 2
  • 3
  • 4
  • quiz
Python
  • Understand inheritance and how classes inherit from each other
  • Override methods in child classes
  • Use super() to call parent methods
  • Understand polymorphism and method overriding

Inheritance and Polymorphism

Imagine you're building a family tree. Your grandparents pass down traits to your parents, who pass them down to you. You inherit some traits but also develop your own unique characteristics.

In programming, inheritance works the same way. A child class can inherit properties and methods from a parent class, but can also add its own unique features or modify inherited ones. This creates a powerful hierarchy of related classes.


Basic Inheritance

Creating a Child Class

class Animal:
    """Parent class for all animals."""
    
    def __init__(self, name, species):
        self.name = name
        self.species = species
    
    def make_sound(self):
        return "Some generic animal sound"
    
    def eat(self, food):
        return f"{self.name} eats {food}"

# Child class inherits from Animal
class Dog(Animal):
    """Dog inherits from Animal."""
    
    def __init__(self, name, breed):
        # Call parent constructor
        super().__init__(name, "Dog")
        # Add dog-specific attribute
        self.breed = breed
    
    # Override parent method
    def make_sound(self):
        return "Woof!"
    
    # Add dog-specific method
    def fetch(self, item):
        return f"{self.name} fetches the {item}"

Using Inheritance

# Create instances
generic_animal = Animal("Generic", "Unknown")
buddy = Dog("Buddy", "Golden Retriever")

print(generic_animal.make_sound())  # "Some generic animal sound"
print(buddy.make_sound())           # "Woof!" (overridden)
print(buddy.eat("bones"))           # "Buddy eats bones" (inherited)
print(buddy.fetch("ball"))          # "Buddy fetches the ball" (new method)

# Check inheritance
print(isinstance(buddy, Dog))       # True
print(isinstance(buddy, Animal))    # True - Dog IS-A Animal
print(isinstance(generic_animal, Dog))  # False

Method Overriding

Child classes can provide their own implementation of inherited methods:

class Bird(Animal):
    def __init__(self, name, can_fly=True):
        super().__init__(name, "Bird")
        self.can_fly = can_fly
    
    def make_sound(self):
        return "Tweet!"
    
    def fly(self):
        if self.can_fly:
            return f"{self.name} flies through the sky!"
        return f"{self.name} cannot fly."

class Penguin(Bird):
    def __init__(self, name):
        super().__init__(name, can_fly=False)  # Penguins can't fly
    
    def make_sound(self):
        return "Honk!"
    
    def swim(self):
        return f"{self.name} swims gracefully in the water!"

The super() Function

super() allows you to call methods from the parent class:

class Cat(Animal):
    def __init__(self, name, lives=9):
        super().__init__(name, "Cat")  # Call parent __init__
        self.lives = lives
    
    def make_sound(self):
        parent_sound = super().make_sound()  # Get parent method result
        return f"Meow! (Also {parent_sound})"
    
    def lose_life(self):
        self.lives -= 1
        if self.lives <= 0:
            return f"{self.name} has no lives left!"
        return f"{self.name} has {self.lives} lives remaining."

Polymorphism

Polymorphism means "many forms." It allows different objects to respond to the same method call in their own way:

# Different animals respond differently to make_sound()
animals = [
    Dog("Buddy", "Golden Retriever"),
    Bird("Tweety", True),
    Cat("Whiskers"),
    Animal("Generic", "Unknown")
]

for animal in animals:
    print(f"{animal.name}: {animal.make_sound()}")

# Output:
# Buddy: Woof.
# Tweety: Tweet.
# Whiskers: Meow! (Also Some generic animal sound)
# Generic: Some generic animal sound

Duck Typing

Python uses "duck typing" - if it walks like a duck and quacks like a duck, it's a duck:

def animal_sounds(animals):
    """Works with any object that has a make_sound method."""
    for animal in animals:
        print(animal.make_sound())

# This works with any object that has make_sound()
class ToyDog:
    def make_sound(self):
        return "Squeak!"

animal_sounds([
    Dog("Buddy", "Golden Retriever"),
    ToyDog()  # Not an Animal, but has make_sound()
])

Shape Hierarchy Example

class Shape:
    """Base class for all shapes."""
    
    def __init__(self, name):
        self.name = name
    
    def area(self):
        """Calculate area - to be overridden by subclasses."""
        raise NotImplementedError("Subclasses must implement area()")
    
    def perimeter(self):
        """Calculate perimeter - to be overridden by subclasses."""
        raise NotImplementedError("Subclasses must implement perimeter()")
    
    def describe(self):
        return f"I am a {self.name}"

class Rectangle(Shape):
    def __init__(self, width, height):
        super().__init__("Rectangle")
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)

class Circle(Shape):
    def __init__(self, radius):
        super().__init__("Circle")
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2
    
    def perimeter(self):
        return 2 * 3.14159 * self.radius

class Triangle(Shape):
    def __init__(self, base, height, side1, side2, side3):
        super().__init__("Triangle")
        self.base = base
        self.height = height
        self.sides = [side1, side2, side3]
    
    def area(self):
        return 0.5 * self.base * self.height
    
    def perimeter(self):
        return sum(self.sides)

Using the Shape Hierarchy

shapes = [
    Rectangle(4, 5),
    Circle(3),
    Triangle(6, 4, 3, 4, 5)
]

for shape in shapes:
    print(f"{shape.describe()}")
    print(f"  Area: {shape.area():.2f}")
    print(f"  Perimeter: {shape.perimeter():.2f}")
    print()

# All shapes respond to the same methods but behave differently.

Multiple Inheritance

Python supports multiple inheritance (inheriting from multiple parents):

class Flyable:
    def fly(self):
        return "I can fly!"

class Swimmable:
    def swim(self):
        return "I can swim!"

class Duck(Flyable, Swimmable, Animal):
    def __init__(self, name):
        super().__init__(name, "Duck")
    
    def make_sound(self):
        return "Quack!"

# Duck inherits from Animal, Flyable, and Swimmable
duck = Duck("Donald")
print(duck.make_sound())  # "Quack!" (from Duck)
print(duck.fly())         # "I can fly!" (from Flyable)
print(duck.swim())        # "I can swim!" (from Swimmable)
print(duck.eat("bread"))  # "Donald eats bread" (from Animal)

Common Inheritance Patterns

1. Abstract Base Classes

from abc import ABC, abstractmethod

class Vehicle(ABC):
    @abstractmethod
    def move(self):
        pass
    
    @abstractmethod
    def stop(self):
        pass

class Car(Vehicle):
    def move(self):
        return "Car drives on road"
    
    def stop(self):
        return "Car applies brakes"

# vehicle = Vehicle()  # Error! Can't instantiate abstract class
car = Car()  # OK

2. Method Resolution Order (MRO)

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

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

Key Points to Remember

  • Inheritance = Child classes inherit from parents using class Child(Parent):
  • Method Overriding = Child provides different implementation with same method name
  • super() = Call parent class methods like super().__init__() or super().method_name()
  • Polymorphism = Same method, different behavior; objects respond differently to same method call
  • Duck Typing = If it quacks like a duck, it's a duck; behavior matters more than inheritance

Inheritance lets classes build upon each other, but how do we protect our object's data? In the next lesson, we'll explore encapsulation and abstraction – the art of hiding complexity and protecting data integrity.

© 2026 forEach. All rights reserved.

Privacy Policy•Terms of Service