Topic 3: Inheritance and Polymorphism

1. Introduction

Inheritance and Polymorphism are two of the four primary pillars of OOP. They allow developers to create a new class based on an existing class (Inheritance) and use them in an interchangeable way (Polymorphism), enhancing code reusability and flexibility.

2. Inheritance

Inheritance enables a new class to inherit attributes and behaviors (methods) from an existing class.

Base Class (or Parent Class)

The class whose properties and methods are inherited by another class.

Derived Class (or Child Class)

The class that inherits properties and methods from another class.

Example:

python
# Base Class class Animal: def __init__(self, species): self.species = species def speak(self): pass # Derived Class class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!"

In the example, Dog and Cat are derived from the Animal class.

The super() Function

It’s often needed to call a method in the parent class from inside the child class, especially when overriding methods. The super() function helps with this.

python
class Bird(Animal): def __init__(self, species, can_fly): super().__init__(species) self.can_fly = can_fly

3. Polymorphism

Polymorphism, from Greek, means “many shapes”. It refers to the ability of different classes to be treated as instances of the same class through inheritance. The classic example is having a method with the same name in both parent and child classes, but the child’s method overrides or extends the parent’s method.

Example using the above classes:

python
def animal_sound(animal): print(animal.speak()) dog = Dog("Golden Retriever") cat = Cat("Persian") animal_sound(dog) # Outputs: Woof! animal_sound(cat) # Outputs: Meow!

In this scenario, despite the animal_sound function designed to accept an Animal type object, due to polymorphism, it can handle any object of derived types (Dog, Cat, etc.) as well.

4. Overriding vs. Overloading

  • Overriding: A derived class has a definition for one of the parent class’s methods that it intends to provide a different implementation for.

  • Overloading: Python doesn’t support method overloading like other languages where you can have multiple methods with the same name but different parameters. However, default parameters and variable-length argument lists (using *args and **kwargs) offer a similar solution.

5. Duck Typing and Polymorphism

Python’s approach to polymorphism is a bit different from strongly typed languages. It employs a concept called “Duck Typing”, which stems from the saying, “If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.”

This means that the type or class of an object is determined by its behavior (methods and properties) rather than its class inheritance.

Example:

python
class Duck: def quack(self): return "Quack!" class Robot: def quack(self): return "Beep quack!" def duck_sound(creature): return creature.quack() duck = Duck() robot = Robot() print(duck_sound(duck)) # Outputs: Quack! print(duck_sound(robot)) # Outputs: Beep quack!

Although Robot doesn’t inherit from Duck, it’s still treated as a “duck” in the duck_sound function due to its quack method.

6. Conclusion

Inheritance and polymorphism are powerful tools in object-oriented programming, enabling developers to write more organized, efficient, and reusable code. By leveraging these concepts, one can model complex systems using simple, maintainable, and extensible code structures.