Intermediate Object-Oriented Programming in Python: Inheritance and Polymorphism

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Overview
  4. Inheritance
  5. Polymorphism
  6. Conclusion

Introduction

In this tutorial, we will explore the concepts of inheritance and polymorphism in object-oriented programming using Python. We will learn how to create and use classes that inherit properties and methods from other classes, as well as how to leverage polymorphism to write flexible and reusable code.

By the end of this tutorial, you will have a solid understanding of inheritance and polymorphism, and you will be able to apply these concepts in your own Python projects.

Prerequisites

To follow along with this tutorial, you should have a basic understanding of object-oriented programming concepts in Python. Familiarity with classes, objects, and methods will be beneficial. Additionally, you should have Python installed on your machine. If you haven’t already installed Python, you can download it from the official Python website (https://www.python.org/downloads/).

Overview

What is Inheritance?

Inheritance is a fundamental concept in object-oriented programming that allows us to create new classes based on existing classes. The class that is being inherited from is called the parent class or superclass, and the class that inherits from it is called the child class or subclass. Inheritance allows the child class to inherit attributes and methods from the parent class, which helps in code reuse and promotes the idea of hierarchical classification of objects.

What is Polymorphism?

Polymorphism is another important concept in object-oriented programming that allows objects of different classes to be treated as objects of a common superclass. This means that a single function or method can be used to work with objects of different types. Polymorphism promotes code flexibility and enables the use of generic, reusable code.

In the sections below, we will dive deeper into inheritance and polymorphism and see how they can be implemented in Python.

Inheritance

In Python, inheritance is implemented using the syntax class ChildClass(ParentClass). This creates a new class (ChildClass) that inherits from an existing class (ParentClass).

Creating a Parent Class

Let’s start by creating a Person class that represents a generic person with attributes like name and age. ```python class Person: def init(self, name, age): self.name = name self.age = age

    def greet(self):
        print(f"Hello, my name is {self.name} and I am {self.age} years old.")

# Create an instance of the Person class
person = Person("Alice", 25)
person.greet()  # Output: Hello, my name is Alice and I am 25 years old.
``` Here, we have defined the `Person` class with an `__init__` method that initializes the `name` and `age` attributes. We have also defined a `greet` method that prints a greeting message using the `name` and `age` attributes.

Creating a Child Class

Now, let’s create a Student class that inherits from the Person class. In addition to the attributes and methods inherited from Person, the Student class will also have a school attribute. ```python class Student(Person): def init(self, name, age, school): super().init(name, age) self.school = school

    def study(self):
        print(f"{self.name} is studying at {self.school}.")

# Create an instance of the Student class
student = Student("Bob", 20, "ABC High School")
student.greet()  # Output: Hello, my name is Bob and I am 20 years old.
student.study()  # Output: Bob is studying at ABC High School.
``` In this example, we define the `Student` class as a subclass of `Person`. The `__init__` method of the `Student` class calls the `__init__` method of the `Person` class using `super()`, but also initializes the `school` attribute.

Now, we can create instances of both the Person class and the Student class. The student object can access the greet method defined in the Person class as well as the study method defined in the Student class.

Method Overriding

In addition to inheriting attributes and methods, child classes can also override methods defined in the parent class. ```python class Student(Person): def init(self, name, age, school): super().init(name, age) self.school = school

    def greet(self):
        print(f"Hello, my name is {self.name}, I am {self.age} years old, and I study at {self.school}.")

student = Student("Bob", 20, "ABC High School")
student.greet()  # Output: Hello, my name is Bob, I am 20 years old, and I study at ABC High School.
``` In this example, we have overridden the `greet` method of the `Person` class in the `Student` class. When we call the `greet` method on a `Student` object, the overridden method in the `Student` class is executed instead of the method in the parent `Person` class.

This allows us to customize the behavior of methods in the child class while still inheriting common functionality from the parent class.

Polymorphism

Polymorphism allows us to treat objects of different classes as if they are of the same type. This enables us to write more generic and flexible code.

Polymorphic Functions

Let’s create a function called introduce that can be used to introduce a Person or a Student object. ```python def introduce(obj): obj.greet()

person = Person("Alice", 25)
student = Student("Bob", 20, "ABC High School")

introduce(person)  # Output: Hello, my name is Alice and I am 25 years old.
introduce(student)  # Output: Hello, my name is Bob, I am 20 years old, and I study at ABC High School.
``` Here, we define the `introduce` function that takes an object as an argument and calls its `greet` method. Since both `Person` and `Student` classes have a `greet` method, we can pass objects of either class to the `introduce` function.

This demonstrates polymorphism in action. The introduce function doesn’t need to know the specific class of the object it receives; it only relies on the fact that the object has a greet method.

Polymorphic Methods

In addition to polymorphic functions, we can also have polymorphic methods within a class hierarchy. ```python class Animal: def sound(self): pass

class Cat(Animal):
    def sound(self):
        print("Meow")

class Dog(Animal):
    def sound(self):
        print("Woof")

animals = [Cat(), Dog()]

for animal in animals:
    animal.sound()
``` In this example, we define an `Animal` class with a `sound` method that doesn't do anything. We then create two subclasses, `Cat` and `Dog`, which override the `sound` method with their own implementation.

We create a list called animals that contains instances of Cat and Dog objects. By iterating over this list and calling the sound method on each object, we can ensure that the appropriate implementation of sound is called based on the actual class of the object.

Conclusion

In this tutorial, we have learned about inheritance and polymorphism in Python. Inheritance allows us to create new classes that inherit properties and methods from existing classes, promoting code reuse and hierarchical classification. Polymorphism enables us to treat objects of different classes as if they are of the same type, allowing for generic and flexible code.

By mastering these concepts, you can write more organized, reusable, and efficient code in your Python projects. Keep practicing and exploring different scenarios to deepen your understanding of object-oriented programming in Python.