Inheritance
Inheritance is a mechanism where a new class (derived class or subclass) inherits attributes and methods from an existing class (base class or superclass). This allows you to create a hierarchy of classes that share common functionality while allowing specialization.
Understanding Inheritance
Section titled “Understanding Inheritance”Inheritance creates an “is-a” relationship. For example:
- A
Caris-aVehicle - A
Dogis-anAnimal - A
Manageris-anEmployee
Basic Inheritance
Section titled “Basic Inheritance”class Vehicle: """Base class (parent/superclass)""" def __init__(self, brand: str, model: str, year: int): self.brand = brand self.model = model self.year = year
def start(self): return f"{self.brand} {self.model} started."
def stop(self): return f"{self.brand} {self.model} stopped."
def get_info(self): return f"{self.brand} {self.model} ({self.year})"
class Car(Vehicle): """Derived class (child/subclass) - inherits from Vehicle""" def __init__(self, brand: str, model: str, year: int, num_doors: int): super().__init__(brand, model, year) # Call parent constructor self.num_doors = num_doors # Additional attribute
def honk(self): """New method specific to Car""" return "Beep beep!"
class Motorcycle(Vehicle): """Another derived class""" def __init__(self, brand: str, model: str, year: int, bike_type: str): super().__init__(brand, model, year) self.bike_type = bike_type # Additional attribute
def wheelie(self): """New method specific to Motorcycle""" return "Doing a wheelie!"
# Usagecar = Car("Toyota", "Camry", 2020, 4)print(car.start()) # Inherited method: "Toyota Camry started."print(car.honk()) # Car-specific method: "Beep beep!"print(car.get_info()) # Inherited method: "Toyota Camry (2020)"
motorcycle = Motorcycle("Yamaha", "YZF-R3", 2021, "Sport")print(motorcycle.start()) # Inherited method: "Yamaha YZF-R3 started."print(motorcycle.wheelie()) # Motorcycle-specific method: "Doing a wheelie!"classDiagram
class Vehicle {
+brand: str
+model: str
+year: int
+start() str
+stop() str
+get_info() str
}
class Car {
+num_doors: int
+honk() str
}
class Motorcycle {
+bike_type: str
+wheelie() str
}
Vehicle <|-- Car
Vehicle <|-- Motorcycle
Method Overriding
Section titled “Method Overriding”Subclasses can override parent methods to provide specialized behavior:
class Vehicle: def __init__(self, brand: str, model: str, year: int): self.brand = brand self.model = model self.year = year
def start(self): return f"{self.brand} {self.model} started."
def fuel_type(self): return "Unknown fuel type"
class Car(Vehicle): def start(self): """Override parent method with specialized behavior""" return f"{self.brand} {self.model} car started with a roar!"
def fuel_type(self): """Override to specify fuel type""" return "Gasoline or Electric"
class ElectricCar(Car): def start(self): """Further override for electric cars""" return f"{self.brand} {self.model} silently started (electric motor)"
def fuel_type(self): """Override to specify electric""" return "Electric"
car = Car("Toyota", "Camry", 2020)print(car.start()) # "Toyota Camry car started with a roar!"print(car.fuel_type()) # "Gasoline or Electric"
electric_car = ElectricCar("Tesla", "Model 3", 2023)print(electric_car.start()) # "Tesla Model 3 silently started (electric motor)"print(electric_car.fuel_type()) # "Electric"Using super()
Section titled “Using super()”The super() function allows you to call methods from the parent class:
class Employee: def __init__(self, name: str, employee_id: int): self.name = name self.employee_id = employee_id
def get_info(self): return f"Employee: {self.name} (ID: {self.employee_id})"
class Manager(Employee): def __init__(self, name: str, employee_id: int, department: str): super().__init__(name, employee_id) # Call parent __init__ self.department = department
def get_info(self): """Extend parent method using super()""" base_info = super().get_info() # Call parent method return f"{base_info}, Department: {self.department}"
class Director(Manager): def __init__(self, name: str, employee_id: int, department: str, budget: float): super().__init__(name, employee_id, department) # Call Manager's __init__ self.budget = budget
def get_info(self): """Further extend using super()""" manager_info = super().get_info() # Call Manager's get_info return f"{manager_info}, Budget: ${self.budget:,.2f}"
manager = Manager("Alice", 101, "Engineering")print(manager.get_info())# "Employee: Alice (ID: 101), Department: Engineering"
director = Director("Bob", 102, "Engineering", 1000000.0)print(director.get_info())# "Employee: Bob (ID: 102), Department: Engineering, Budget: $1,000,000.00"Real-World Example: E-commerce System
Section titled “Real-World Example: E-commerce System”class Product: """Base class for all products""" def __init__(self, name: str, price: float, sku: str): self.name = name self.price = price self.sku = sku
def calculate_shipping(self, weight: float) -> float: """Base shipping calculation""" return weight * 2.5 # $2.5 per kg
def get_info(self) -> str: return f"{self.name} - ${self.price:.2f} (SKU: {self.sku})"
class DigitalProduct(Product): """Digital products - no shipping""" def __init__(self, name: str, price: float, sku: str, download_size: float): super().__init__(name, price, sku) self.download_size = download_size # in MB
def calculate_shipping(self, weight: float) -> float: """Override - digital products have no shipping cost""" return 0.0
def get_info(self) -> str: base_info = super().get_info() return f"{base_info} - Digital Download ({self.download_size} MB)"
class PhysicalProduct(Product): """Physical products with weight""" def __init__(self, name: str, price: float, sku: str, weight: float): super().__init__(name, price, sku) self.weight = weight # in kg
def calculate_shipping(self, weight: float = None) -> float: """Override - use product's own weight""" actual_weight = weight if weight else self.weight return super().calculate_shipping(actual_weight)
def get_info(self) -> str: base_info = super().get_info() return f"{base_info} - Weight: {self.weight} kg"
class FragileProduct(PhysicalProduct): """Fragile products need special handling""" def __init__(self, name: str, price: float, sku: str, weight: float): super().__init__(name, price, sku, weight)
def calculate_shipping(self, weight: float = None) -> float: """Override - add handling fee for fragile items""" base_shipping = super().calculate_shipping(weight) handling_fee = 10.0 # Additional $10 for fragile items return base_shipping + handling_fee
def get_info(self) -> str: base_info = super().get_info() return f"{base_info} - FRAGILE"
# Usageebook = DigitalProduct("Python Guide", 29.99, "DIG-001", 5.2)print(ebook.get_info())print(f"Shipping: ${ebook.calculate_shipping(0):.2f}")
book = PhysicalProduct("Python Book", 39.99, "PHY-001", 0.5)print(book.get_info())print(f"Shipping: ${book.calculate_shipping():.2f}")
vase = FragileProduct("Ceramic Vase", 49.99, "FRG-001", 1.2)print(vase.get_info())print(f"Shipping: ${vase.calculate_shipping():.2f}")Multiple Inheritance
Section titled “Multiple Inheritance”Python supports multiple inheritance - a class can inherit from multiple parent classes:
class Flyable: def fly(self): return "Flying through the air"
class Swimmable: def swim(self): return "Swimming in water"
class Duck(Flyable, Swimmable): """Duck can both fly and swim""" def __init__(self, name: str): self.name = name
def quack(self): return f"{self.name} says quack!"
duck = Duck("Donald")print(duck.fly()) # From Flyableprint(duck.swim()) # From Swimmableprint(duck.quack()) # Duck's own methodMethod Resolution Order (MRO)
Section titled “Method Resolution Order (MRO)”When using multiple inheritance, Python uses Method Resolution Order to determine which method to call:
class A: def method(self): return "A"
class B(A): def method(self): return "B"
class C(A): def method(self): return "C"
class D(B, C): pass
d = D()print(d.method()) # "B" - B comes before C in MROprint(D.__mro__) # Shows the method resolution orderKey Takeaways
Section titled “Key Takeaways”- Inheritance creates an “is-a” relationship between classes
- Subclasses inherit all attributes and methods from parent classes
- Method overriding allows subclasses to provide specialized behavior
super()is used to call parent class methods- Multiple inheritance allows a class to inherit from multiple parents
- MRO determines the order in which methods are resolved in multiple inheritance
- Use inheritance to reuse code and create specialized classes from general ones
Inheritance is powerful for creating class hierarchies where specialized classes extend and customize the behavior of more general classes.