Learning Objectives
- Understand the concept of polymorphism.
- Learn the function polymorphism, class polymorphism, and inheritance class polymorphism.
- Learn how to use isinstance() method
14-1. Overview
In programming, polymorphism refers to the ability of different objects to respond to the same message (method call) in different ways. This allows for more flexible and modular code, as methods can be written to accept objects of a superclass, and then different subclasses can provide their own implementations of those methods. This concept is fundamental to object-oriented programming (OOP) and is often associated with inheritance and dynamic dispatch. The word "polymorphism" indeed comes from the Greek roots "poly" meaning "many" and "morph" meaning "form", so it literally translates to "many forms".
14-2. Function Polymorphism
Function Polymorphism
- Function polymorphism means that a single function can operate on different types of data and behave appropriately based on the type of the argument(s).
- Python supports function polymorphism through dynamic typing and overloading behavior of built-in and user-defined functions.
Built-in Function Polymorphism
- Python has many built-in functions that demonstrate polymorphism.
- These functions can take different types of inputs and behave accordingly.
- Although len() is a single function, it works with multiple data types by calling each type's special method: __len__() in str, list, tuple, dict, etc.
-
Actually, while the len() function can indeed be used to return the number of characters in a string or the number of elements in a list, its behavior isn't limited to just those data types. The len() function is a built-in Python function that can be applied to any object that supports the concept of "length" or "size".
The len() function is designed to return the length (number of items) of an object. The specific way it calculates the length depends on the type of the object it's operating on. This ability to handle different types of objects is what makes len() polymorphic.
-
The len() function is natively supported for several built-in types:
- Strings: Returns the number of characters in the string.
- Lists: Returns the number of elements in the list.
- Tuples: Returns the number of elements in the tuple.
- Dictionaries: Returns the number of key-value pairs.
- Sets: Returns the number of elements in the set.
User-Defined Function Polymorphism
- You can write your own functions that accept arguments of different types and behave accordingly.
- Here, the function double() behaves differently depending on the input type — it multiplies a number or repeats a string/list
Function Overloading (Simulated)
- Unlike some other languages (e.g., Java or C++), Python does not support traditional function overloading (same function name with different parameter lists). However, you can simulate it using:
- Default parameters
- Variable-length arguments (*args, **kwargs)
- Type checking inside the function
14-3. Operator Polymorphism
Operator Polymorphism
- Operator polymorphism means that the same operator can behave differently depending on the type of operands.
- In Python, operators like +, *, ==, etc., are overloaded by default for various data types.
Built-in Operator Polymorphism
- The meaning of an operator depends on the data types involved.
- Although the operator is the same (+), it performs different operations:
- Numeric addition for numbers
- Concatenation for strings and lists
- Comparison Operators
- Operators like ==, !=, <, > also behave differently based on data types.
Custom Operator Polymorphism (Operator Overloading)
- You can define or change the behavior of operators for user-defined classes by overriding special methods.
Example: Custom + Operator with Classes
- Here, the + operator is polymorphic because it works for integers, floats, strings, lists, and even custom objects like Book.
Example: Overloading Comparison Operators
- The > operator works here because we defined __gt__.
14-4. Class Polymorphism
Class Polymorphism
- Class polymorphism means that objects of different classes can be used interchangeably, as long as they implement a common interface (i.e., same method names or behavior). This is usually achieved through inheritance and method overriding.
- This allows you to write general-purpose code that works with a variety of classes, increasing flexibility and reducing redundancy.
Polymorphism via Inheritance (Method Overriding)
- When a subclass defines a method with the same name as one in its parent class, it overrides the method. You can then use these classes polymorphically.
- Even though all objects are treated as Animal, the actual method executed is from the actual
class (Dog, Cat, etc.). - This is classic class-based polymorphism.
Using Polymorphic Functions with Different Classes
- A function can accept different types of objects as long as they implement the required methods — this is polymorphism in action.
- Even though Duck and Person are unrelated classes, the function sound_test() works because both implement make_sound().
- This is also called interface-based polymorphism (or duck typing in Python).
Polymorphism with Abstract Base Classes (ABC)
- In more formal designs, polymorphism is enforced using abstract base classes, which require subclasses to implement certain methods.
- Shape defines a common interface (area()).
- Subclasses implement their own logic.
- You can treat all of them as Shape objects: a powerful example of class polymorphism.
Duck Typing
- “If it walks like a duck and quacks like a duck, it's a duck.”
- Duck typing is a type of dynamic (runtime) polymorphism in Python where an object’s suitability is determined by the presence of certain methods or properties, rather than the actual type of the object.
- In other words, Python cares more about what an object can do than what it is.
Example: Duck Typing
- Duck and Person are unrelated classes.
- The make_it_quack() function works with both because they have a quack() method.
Duck Typing vs Inheritance (Inheritance Approach)
- Inheritance-based polymorphism requires a common base class.
-
No base class needed: as long as speak() exists, the function works.
Example with File-like Objects
- This is a real-world use of duck typing in Python's built-in libraries.
- Here, read_data() doesn’t care whether it’s dealing with an actual file or a string buffer — as long as the object has a read() method, it works.
Caution with Duck Typing
- Since Python is dynamically typed, duck typing can lead to runtime errors if the expected method or attribute is missing.
- To avoid this, one option is to use hasattr() to check:
- Another option is to use try/catch to handel errors:
14-5. Abstract Base Classes (ABC)
Abstract Base Classes (ABC)
- An Abstract Base Class (ABC) is a class that cannot be instantiated on its own. It is designed to define a common interface (a set of method names and signatures) that subclasses must implement.
- Polymorphism occurs when different subclasses implement these methods in different ways, and code can work with any of the subclasses interchangeably through the abstract base class interface.
- An abstract class is a class that contains only a list of methods and is used to enforce method implementation in the inheriting classes
- An abstract method is a method that has a declaration but does not have an implementation
- Import Abstract Base Class
import ABC
- Import Abstract Base Class
- The @abstractmethod decorator is used to define an abstract method within an abstract base class (ABC)
How to Define an Abstract Base Class
- Python provides the abc module for this.
- ABC is the base class for all abstract classes.
- @abstractmethod is used to mark methods that must be implemented in a subclass.
Example: Polymorphism with ABC
Step 1: Define an abstract base class.
- This defines the interface all shapes must follow.
Step 2: Create concrete subclasses
- Each subclass provides its own implementation of area() and perimeter().
Step 3: Use them polymorphically
- Even though Rectangle and Circle are different classes, the function print_shape_info() works with both — this is polymorphism through ABCs.
isinstance() function
The isinstance() function in Python is used to check if an object is an instance of a specified class or if it is an instance of a subclass of that class.
Here's the general syntax:
isinstance(object, classinfo) |
- object: The object to be checked
- classinfo: A class or a tuple of classes to be checked against
In the above example, car_instance is an instance of both the Car class and its parent class Vehicle, so isinstance() returns True for both checks.
Output:
True True |
Summary
- Polymorphism refers to the ability of different objects to respond to the same message (method call) in different ways.
- len() is a built-in Python function that can be applied to any object that supports the concept of "length" or "size".
- Polymorphism in object-oriented programming allows for methods with the same name to behave differently depending on the object that calls them.
- Each subclass inherits methods from the superclass and can override methods as needed.
- You can use isinstance() function to check if an object is an instance of a specified class or if it is an instance of a subclass of that class.
Programming Exercises
Exercise 1: Shape Area Calculation
Write a program that calculates the area of different shapes (circle, square, rectangle) using polymorphism. Define a base class Shape with a method calculate_area(). Then create subclasses for each shape (e.g., Circle, Square, Rectangle) and override the calculate_area() method in each subclass to calculate the area according to the shape's specific formula.
Exercise 2: Animal Sounds
Write a program that simulates different animals making sounds using polymorphism. Define a base class Animal with a method make_sound(). Then create subclasses for different animals (e.g., dog, cat, bird) and override the make_sound() method in each subclass to produce the appropriate sound.
Exercise 3: Employee Payment Calculation
Write a program that calculates payments for employees based on their roles using polymorphism. Define a base class Employee with a method calculate_payment(). Then create subclasses for different roles (e.g., Manager, Developer, Intern) and override the calculate_payment() method in each subclass to calculate payments based on their specific rules (e.g., hourly rate, monthly salary).
Exercise 4: Vehicle Simulation
Write a program that simulates different types of vehicles (car, bicycle, motorcycle) using polymorphism. Define a base class Vehicle with methods accelerate() and brake(). Then create subclasses for each type of vehicle and override the accelerate() and brake() methods to simulate the behavior of each vehicle type.
Exercise 5: isinstance() Function
Develop a function that behaves differently based on the type of input using isinstance(). Define a function calculate_area() that calculates the area of a circle if the input is a Circle object and the area of a rectangle if the input is a Rectangle object.