Inheritance

Back

Loading concept...

🎭 The Family Tree of Code: Understanding Inheritance in Python

Imagine you’re building a toy factory. Instead of creating each toy from scratch, what if you could say “this new toy is like THAT toy, but with a few extras”? That’s inheritance!


🌳 The Big Picture: What is Inheritance?

Think of your family. You might have your mom’s eyes and your dad’s smile. You inherited these traits from your parents. In Python, classes can do the same thing!

Inheritance lets one class (the child) borrow all the abilities from another class (the parent). The child gets everything the parent has — and can add its own special powers too!

class Parent:
    def say_hello(self):
        print("Hello!")

class Child(Parent):
    pass  # Child gets say_hello for free!

kid = Child()
kid.say_hello()  # Prints: Hello!

🔗 Single Inheritance: One Parent, One Child

Single inheritance is like having exactly one parent to learn from.

🎨 The Analogy

Imagine a basic cake recipe (parent). Now you want to make a chocolate cake (child). You don’t rewrite the whole recipe — you just say “it’s like the basic cake, but add chocolate!”

📝 Example

class Animal:
    def breathe(self):
        print("Breathing...")

    def eat(self):
        print("Eating...")

class Dog(Animal):
    def bark(self):
        print("Woof!")

buddy = Dog()
buddy.breathe()  # From Animal
buddy.bark()     # Dog's own ability

What happened?

  • Dog inherits from Animal
  • Dog automatically gets breathe() and eat()
  • Dog adds its own bark() method
graph TD A["Animal 🐾"] --> B["Dog 🐕"] A --> |"breathe#40;#41;, eat#40;#41;"| B B --> |"adds bark#40;#41;"| B

🔄 Method Overriding: “I’ll Do It My Way!”

Sometimes a child wants to do something differently than the parent. That’s called method overriding.

🎨 The Analogy

Your mom makes pasta with tomato sauce. You learned her recipe, but YOU prefer adding cheese on top. You override her method with your own version!

📝 Example

class Bird:
    def move(self):
        print("Flying high!")

class Penguin(Bird):
    def move(self):  # Override!
        print("Swimming fast!")

tux = Penguin()
tux.move()  # Prints: Swimming fast!

What happened?

  • Penguin is a Bird
  • But penguins can’t fly — they swim!
  • We override the move() method
graph TD A["Bird 🐦"] --> B["Penguin 🐧"] A --> |"move#40;#41; = fly"| A B --> |"move#40;#41; = swim"| B style B fill:#e1f5fe

🦸 Using super(): Calling Your Parent’s Power

What if you want to use your parent’s method AND add something extra? Use super()!

🎨 The Analogy

Your parent taught you to make a sandwich. You use super() to make their sandwich first, THEN you add your own special sauce on top!

📝 Example

class Phone:
    def __init__(self):
        self.can_call = True
        print("Basic phone ready!")

class SmartPhone(Phone):
    def __init__(self):
        super().__init__()  # Parent's init
        self.has_apps = True
        print("Apps installed!")

my_phone = SmartPhone()
# Prints: Basic phone ready!
# Prints: Apps installed!

Why use super()?

  • ✅ Get everything the parent does
  • ✅ Then add your own extras
  • ✅ No need to copy-paste parent’s code

🔥 Real Example: Building on Parent

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

    def describe(self):
        return f"Employee: {self.name}"

class Manager(Employee):
    def __init__(self, name, team_size):
        super().__init__(name)  # Parent sets name
        self.team_size = team_size

    def describe(self):
        base = super().describe()  # Get parent's text
        return f"{base}, leads {self.team_size} people"

boss = Manager("Alice", 5)
print(boss.describe())
# Employee: Alice, leads 5 people

👨‍👩‍👦 Multiple Inheritance: Two Parents!

Multiple inheritance means a child can have MORE than one parent. It gets powers from ALL of them!

🎨 The Analogy

Imagine a flying car. It inherits abilities from BOTH a Car (drive on roads) AND an Airplane (fly in sky)!

📝 Example

class Swimmer:
    def swim(self):
        print("Swimming!")

class Climber:
    def climb(self):
        print("Climbing!")

class Adventurer(Swimmer, Climber):
    def explore(self):
        print("Exploring everywhere!")

alex = Adventurer()
alex.swim()    # From Swimmer
alex.climb()   # From Climber
alex.explore() # Own method
graph TD A["Swimmer 🏊"] --> C["Adventurer 🧗"] B["Climber 🧗"] --> C C --> |"swim + climb + explore"| C

⚠️ Be Careful!

What if both parents have the same method name? Python needs to decide which one to use…


🗺️ Method Resolution Order (MRO): The Search Map

When you call a method, Python searches for it in a specific order. This order is called the MRO.

🎨 The Analogy

Lost something? You search:

  1. Your pocket first (the child class)
  2. Then ask your first parent
  3. Then your second parent
  4. Finally, grandparents

Python follows the same pattern!

📝 How to See the MRO

class A:
    def greet(self):
        print("Hello from A")

class B(A):
    def greet(self):
        print("Hello from B")

class C(A):
    def greet(self):
        print("Hello from C")

class D(B, C):
    pass

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

d = D()
d.greet()  # Prints: Hello from B

The Search Order:

  1. Look in D — not found
  2. Look in B — FOUND! Use this one
graph TD A["A"] --> B["B"] A --> C["C"] B --> D["D"] C --> D D --> |"Search: D→B→C→A"| D

🔑 Remember

  • Python uses C3 Linearization (fancy term for “smart ordering”)
  • Always checks left parent before right parent
  • Never visits the same class twice

🧩 Mixins: Little Helper Classes

A mixin is a small class that adds ONE specific feature. It’s not meant to be used alone — only mixed into other classes!

🎨 The Analogy

Think of mixins like ice cream toppings. You don’t eat just sprinkles alone. You ADD sprinkles to ice cream. The sprinkles are the mixin!

📝 Example

class LoggerMixin:
    def log(self, message):
        print(f"[LOG] {message}")

class TimestampMixin:
    def get_time(self):
        from datetime import datetime
        return datetime.now().strftime("%H:%M")

class App(LoggerMixin, TimestampMixin):
    def run(self):
        self.log(f"Started at {self.get_time()}")

my_app = App()
my_app.run()
# [LOG] Started at 14:30

🎯 Why Use Mixins?

Without Mixins With Mixins
Copy-paste logging code everywhere Add LoggerMixin to any class
Repeat timestamp code Add TimestampMixin anywhere
Classes become huge Keep classes small & focused

📝 Real Example: JSON Mixin

import json

class JsonMixin:
    def to_json(self):
        return json.dumps(self.__dict__)

class User(JsonMixin):
    def __init__(self, name, age):
        self.name = name
        self.age = age

user = User("Bob", 25)
print(user.to_json())
# {"name": "Bob", "age": 25}

Any class can now convert itself to JSON just by adding JsonMixin!


🎓 Quick Summary

Concept What It Does Example
Single Inheritance One parent → one child class Dog(Animal)
Method Overriding Child replaces parent’s method Define same method name
super() Call parent’s method super().__init__()
Multiple Inheritance Many parents → one child class C(A, B)
MRO Order Python searches for methods ClassName.__mro__
Mixins Small helper classes for one feature class App(LoggerMixin)

🚀 You Got This!

Inheritance is like building with LEGO blocks. Instead of creating every piece from scratch:

  1. Start with what exists (parent class)
  2. Add your own pieces (new methods)
  3. Change what doesn’t fit (override)
  4. Combine multiple blocks (multiple inheritance)
  5. Mix in special features (mixins)

Now you can write cleaner, shorter, and more powerful Python code. Your future self will thank you! 🎉

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.