Section

Inheritance: Creating Hierarchies of Objects

Part of The Prince Academy's AI & DX engineering stack.

Follow The Prince Academy Inc.

Welcome to the fascinating world of Inheritance, a cornerstone of Object-Oriented Programming! Imagine you're building a game and you have a Character class. Now, you want to create different types of characters, like Warrior and Mage. Both Warrior and Mage share common traits with Character (like having health, a name, and the ability to move), but they also have unique abilities. Inheritance allows us to model this relationship by creating a hierarchy of objects, where a more specialized class (like Warrior) can inherit properties and behaviors from a more general class (like Character). This promotes code reuse and makes your programs more organized and maintainable.

In Python, we achieve inheritance by defining a new class that 'inherits' from an existing class. The existing class is called the parent class (or superclass/base class), and the new class is called the child class (or subclass/derived class). The child class automatically gains access to all the attributes and methods of its parent class. Think of it like passing down traits from parents to children.

class Parent:
    def __init__(self, parent_attribute):
        self.parent_attribute = parent_attribute

    def parent_method(self):
        print(f"This is a method from the Parent class with attribute: {self.parent_attribute}")

class Child(Parent):
    def __init__(self, parent_attribute, child_attribute):
        # Call the parent class's constructor
        super().__init__(parent_attribute)
        self.child_attribute = child_attribute

    def child_method(self):
        print(f"This is a method from the Child class with attribute: {self.child_attribute}")

# Creating an instance of the Child class
my_child = Child("from parent", "from child")

# Accessing inherited attribute and method
print(my_child.parent_attribute)
my_child.parent_method()

# Accessing child's attribute and method
print(my_child.child_attribute)
my_child.child_method()

Let's break down the code snippet above:

  1. class Parent:: We define our Parent class with an initializer (__init__) that sets a parent_attribute and a method parent_method.
  2. class Child(Parent):: This is where the magic of inheritance happens. By putting Parent in parentheses after Child, we signify that Child inherits from Parent.
  3. super().__init__(parent_attribute): Inside the Child's __init__, the super() function is crucial. It allows us to call the methods of the parent class. Here, we're calling the Parent's __init__ method to ensure that the parent_attribute is properly initialized.
  4. self.child_attribute = child_attribute: We then initialize the Child's own specific attribute.
  5. child_method(self): The Child class also has its own unique method.
  6. my_child = Child(...): When we create an instance of Child, it has access to both the attributes and methods defined in Child and those inherited from Parent.
graph TD;
    Parent --> Child;
    Parent -- has attribute/method --> ParentAttribute;
    Parent -- has attribute/method --> ParentMethod;
    Child -- has attribute/method --> ChildAttribute;
    Child -- has attribute/method --> ChildMethod;
    Child -- inherits --> Parent;

This diagram illustrates the hierarchical relationship. The Child class is a specialization of the Parent class. It gains all the capabilities of the Parent and adds its own unique features.

Inheritance is a powerful tool for building complex software. It promotes a 'is-a' relationship (e.g., a Warrior 'is a' Character), encourages modularity, and significantly reduces the need to write repetitive code. In the next sections, we'll explore how to extend and override parent class methods, further customizing our inherited classes.