Python Inheritance
Inheritance allows a class (child/subclass) to inherit attributes and methods from another class (parent/superclass). It promotes code reuse and establishes a natural hierarchy between classes.
Basic Inheritance
python
# Parent (Base) class
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def speak(self):
return f"{self.name} makes a sound"
def info(self):
return f"{self.name} is a {self.species}"
# Child (Derived) class
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "Dog") # Call parent constructor
self.breed = breed
def speak(self): # Override parent method
return f"{self.name} says Woof!"
def fetch(self): # New method
return f"{self.name} fetches the ball!"
class Cat(Animal):
def __init__(self, name, indoor=True):
super().__init__(name, "Cat")
self.indoor = indoor
def speak(self):
return f"{self.name} says Meow!"
# Usage
dog = Dog("Buddy", "Golden Retriever")
cat = Cat("Whiskers")
print(dog.speak()) # Buddy says Woof!
print(dog.info()) # Buddy is a Dog (inherited method)
print(dog.fetch()) # Buddy fetches the ball!
print(cat.speak()) # Whiskers says Meow!The super() Function
super() calls the parent class's methods:
python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hi, I'm {self.name}"
class Employee(Person):
def __init__(self, name, age, company, salary):
super().__init__(name, age) # Initialize Person attributes
self.company = company
self.salary = salary
def greet(self):
# Call parent's greet and extend it
base = super().greet()
return f"{base}, I work at {self.company}"
emp = Employee("Alice", 30, "BigXStar", 95000)
print(emp.greet()) # Hi, I'm Alice, I work at BigXStar
print(emp.name) # Alice (inherited attribute)
print(emp.salary) # 95000Types of Inheritance
Single Inheritance
One parent, one child:
python
class Vehicle:
def __init__(self, brand, speed):
self.brand = brand
self.speed = speed
class Car(Vehicle):
def __init__(self, brand, speed, doors):
super().__init__(brand, speed)
self.doors = doorsMultiple Inheritance
One child, multiple parents:
python
class Flyable:
def fly(self):
return "I can fly!"
class Swimmable:
def swim(self):
return "I can swim!"
class Duck(Flyable, Swimmable):
def quack(self):
return "Quack!"
duck = Duck()
print(duck.fly()) # I can fly!
print(duck.swim()) # I can swim!
print(duck.quack()) # Quack!Multilevel Inheritance
Chain of inheritance:
python
class Animal:
def breathe(self):
return "I breathe"
class Mammal(Animal):
def feed_young(self):
return "I feed my young with milk"
class Dog(Mammal):
def bark(self):
return "Woof!"
dog = Dog()
print(dog.breathe()) # I breathe (from Animal)
print(dog.feed_young()) # I feed my young with milk (from Mammal)
print(dog.bark()) # Woof! (own method)Method Resolution Order (MRO)
When using multiple inheritance, Python follows the MRO to determine which method to call:
python
class A:
def greet(self):
return "Hello from A"
class B(A):
def greet(self):
return "Hello from B"
class C(A):
def greet(self):
return "Hello from C"
class D(B, C):
pass
d = D()
print(d.greet()) # Hello from B (B comes before C)
# View the MRO
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
# Or use mro() method
for cls in D.mro():
print(cls.__name__)
# D → B → C → A → objectisinstance() and issubclass()
python
class Animal:
pass
class Dog(Animal):
pass
class Cat(Animal):
pass
dog = Dog()
# isinstance - check if object is an instance of a class
print(isinstance(dog, Dog)) # True
print(isinstance(dog, Animal)) # True (parent counts!)
print(isinstance(dog, Cat)) # False
# issubclass - check class hierarchy
print(issubclass(Dog, Animal)) # True
print(issubclass(Cat, Animal)) # True
print(issubclass(Dog, Cat)) # False
print(issubclass(Animal, object)) # True (everything inherits object)Mixins
Mixins are classes designed to add functionality through multiple inheritance:
python
class JsonMixin:
"""Adds JSON serialization capability."""
def to_json(self):
import json
return json.dumps(self.__dict__, indent=2)
class LogMixin:
"""Adds logging capability."""
def log(self, message):
print(f"[{self.__class__.__name__}] {message}")
class User(JsonMixin, LogMixin):
def __init__(self, name, email):
self.name = name
self.email = email
user = User("Alice", "alice@example.com")
print(user.to_json())
# {
# "name": "Alice",
# "email": "alice@example.com"
# }
user.log("User created")
# [User] User createdPractical Example: Shape Hierarchy
python
"""
Shape hierarchy demonstrating inheritance.
"""
import math
class Shape:
def __init__(self, color="black"):
self.color = color
def area(self):
raise NotImplementedError("Subclasses must implement area()")
def perimeter(self):
raise NotImplementedError("Subclasses must implement perimeter()")
def describe(self):
return (
f"{self.__class__.__name__} ({self.color}): "
f"Area={self.area():.2f}, Perimeter={self.perimeter():.2f}"
)
class Circle(Shape):
def __init__(self, radius, color="black"):
super().__init__(color)
self.radius = radius
def area(self):
return math.pi * self.radius ** 2
def perimeter(self):
return 2 * math.pi * self.radius
class Rectangle(Shape):
def __init__(self, width, height, color="black"):
super().__init__(color)
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
class Square(Rectangle):
def __init__(self, side, color="black"):
super().__init__(side, side, color)
# Usage
shapes = [
Circle(5, "red"),
Rectangle(4, 6, "blue"),
Square(3, "green"),
]
for shape in shapes:
print(shape.describe())
# Circle (red): Area=78.54, Perimeter=31.42
# Rectangle (blue): Area=24.00, Perimeter=20.00
# Square (green): Area=9.00, Perimeter=12.00
# Polymorphism in action
total_area = sum(s.area() for s in shapes)
print(f"\nTotal area: {total_area:.2f}")Summary
- Inheritance lets child classes inherit attributes and methods from parent classes
super()calls the parent class's methods (especially__init__)- Python supports single, multiple, and multilevel inheritance
- MRO (Method Resolution Order) determines which method to call in diamond hierarchies
- Use
isinstance()to check object types andissubclass()for class relationships - Mixins add reusable functionality through multiple inheritance
- Always call
super().__init__()in child constructors to initialize parent attributes
Next, we'll learn about polymorphism in Python.