×
   ❮   
PYTHON FOR DJANGO DJANGO FOR BEGINNERS DJANGO SPECIFICS Roadmap
     ❯   

OOP IN PYTHON

Inheritance

Understanding Inheritance in Python

Introduction

Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows a new class to derive attributes and methods from an existing class. Inheritance promotes code reusability and establishes a natural hierarchy between classes. In Python, inheritance plays a crucial role in Django, where models, views, and forms often benefit from this mechanism to create efficient and maintainable code.

Basics of Inheritance

In inheritance, a new class (known as the child or subclass) inherits properties and behaviors from an existing class (known as the parent or superclass). The child class can extend or override the functionality of the parent class, allowing for a more specialized or refined implementation.

Example:


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

    def speak(self):
        return "Some generic sound"

class Dog(Animal):
    def speak(self):
        return "Woof!"

dog = Dog("Buddy")
print(dog.name)   # Outputs: Buddy
print(dog.speak()) # Outputs: Woof!

In this example, the Dog class inherits from the Animal class. The Dog class has access to the name attribute and the speak method from the Animal class, but it overrides the speak method to provide a more specific implementation.

Types of Inheritance

Python supports several types of inheritance, each serving different needs:

  • Single Inheritance: A subclass inherits from a single parent class.
  • Multiple Inheritance: A subclass inherits from more than one parent class. This allows the subclass to combine attributes and methods from multiple sources.
  • Multilevel Inheritance: A subclass inherits from another subclass, forming a chain of inheritance.
  • Hierarchical Inheritance: Multiple subclasses inherit from a single parent class.
  • Hybrid Inheritance: A combination of two or more types of inheritance.

Single Inheritance Example:


class Vehicle:
    def __init__(self, make):
        self.make = make

class Car(Vehicle):
    def display_make(self):
        return f"Make: {self.make}"

car = Car("Toyota")
print(car.display_make())  # Outputs: Make: Toyota

Multiple Inheritance Example:


class Engine:
    def start(self):
        return "Engine started"

class Radio:
    def play_music(self):
        return "Playing music"

class Car(Engine, Radio):
    def __init__(self, make):
        self.make = make

car = Car("Toyota")
print(car.start())        # Outputs: Engine started
print(car.play_music())  # Outputs: Playing music

Multilevel Inheritance Example:


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

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

class Manager(Employee):
    def __init__(self, name, employee_id, department):
        super().__init__(name, employee_id)
        self.department = department

manager = Manager("Alice", "E123", "Sales")
print(manager.name)         # Outputs: Alice
print(manager.employee_id)  # Outputs: E123
print(manager.department)   # Outputs: Sales

Hierarchical Inheritance Example:


class Shape:
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        import math
        return math.pi * (self.radius ** 2)

class Square(Shape):
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side * self.side

circle = Circle(5)
square = Square(4)
print(circle.area())  # Outputs: 78.53981633974483
print(square.area())  # Outputs: 16

Hybrid Inheritance Example:


class A:
    def method_a(self):
        return "Method A"

class B(A):
    def method_b(self):
        return "Method B"

class C(A):
    def method_c(self):
        return "Method C"

class D(B, C):
    pass

d = D()
print(d.method_a())  # Outputs: Method A
print(d.method_b())  # Outputs: Method B
print(d.method_c())  # Outputs: Method C

Inheritance in Django Models

In Django, inheritance allows you to create models that derive from other models. This is particularly useful for creating a base model with common fields and methods, which can then be extended by other models. Django supports three types of model inheritance:

  • Abstract Base Classes: Used to define a common set of fields and methods that can be inherited by other models. Abstract base classes are not themselves created in the database.
  • Multi-table Inheritance: Allows you to create a base model that is represented in the database, with child models that inherit from it and have their own database tables.
  • Proxy Models: Used to modify the behavior of an existing model without changing its fields. Proxy models are useful for adding custom methods or modifying the default behavior.

Abstract Base Classes Example:


from django.db import models

class CommonInfo(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class Product(CommonInfo):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

In this example, the CommonInfo class is an abstract base class that provides common fields. The Product model inherits from CommonInfo and adds specific fields for products.

Multi-table Inheritance Example:


class Animal(models.Model):
    name = models.CharField(max_length=100)

class Dog(Animal):
    breed = models.CharField(max_length=100)

class Cat(Animal):
    color = models.CharField(max_length=100)

In this example, both Dog and Cat inherit from the Animal model. Each subclass has its own table in the database, and Django manages the relationships between them.

Proxy Models Example:


class Employee(models.Model):
    name = models.CharField(max_length=100)
    position = models.CharField(max_length=100)

class Manager(Employee):
    class Meta:
        proxy = True

    def is_manager(self):
        return True

In this example, the Manager class is a proxy model for the Employee model. It does not have its own database table but adds the is_manager method to enhance the behavior of Employee objects.

Conclusion

Inheritance is a powerful mechanism that enhances code reusability and organization in Python and Django. By understanding and applying different types of inheritance, you can create well-structured, maintainable, and efficient codebases. Whether working with standard Python classes or Django models, leveraging inheritance allows you to build more complex and specialized systems with ease.