Introduction to Polymorphism in Python
Polymorphism is a fundamental concept in object-oriented programming that allows objects of different classes to be treated as objects of a common superclass. The term "polymorphism" means "many shapes," which refers to the ability of different objects to respond to the same method or function in different ways. This concept enhances flexibility and code reusability.
Basic Concepts of Polymorphism
Definition: Polymorphism allows methods to do different things based on the object it is acting upon. It enables a single interface to represent different underlying forms (data types).
Types of Polymorphism:
Method Overloading: Defining multiple methods with the same name but different parameters within the same class. Python does not support traditional method overloading natively; however, you can use default parameters or variable-length arguments to achieve similar behavior.
Method Overriding: Redefining a method in a subclass that was already defined in its superclass. This allows the subclass to provide a specific implementation of a method that overrides the implementation in the superclass.
Detailed Explanation of Polymorphism
1. Method Overriding:
Method overriding occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. This allows the subclass to modify or extend the behavior of the method.
Example:
class Animal:
def speak(self):
return "Animal makes a sound"
class Dog(Animal):
def speak(self):
return "Dog barks"
class Cat(Animal):
def speak(self):
return "Cat meows"
# Demonstrating Polymorphism
animals = [Dog(), Cat()]
for animal in animals:
print(animal.speak())
Output:
Dog barks
Cat meows
In this example, both Dog
and Cat
classes override the speak
method from the Animal
superclass. Despite using the same method name, each subclass provides its own implementation of the speak
method, demonstrating polymorphism.
2. Polymorphism with Function Arguments:
Polymorphism allows functions to accept objects of different types and still perform operations on them as long as they support the same interface or method.
Example:
def make_animal_speak(animal):
print(animal.speak())
# Create instances
dog = Dog()
cat = Cat()
# Use polymorphism to call the method
make_animal_speak(dog)
make_animal_speak(cat)
Output:
Dog barks
Cat meows
In this case, the make_animal_speak
function can accept any object that has a speak
method, demonstrating polymorphism.
Common Interview Questions on Polymorphism
1. What is polymorphism in object-oriented programming?
Polymorphism in object-oriented programming is the ability of different objects to be treated as instances of the same class through a common interface. It allows methods to be implemented in multiple ways depending on the object.
2. How does method overriding differ from method overloading?
Method overriding involves redefining a method in a subclass that is already defined in its superclass, allowing the subclass to provide a specific implementation. Method overloading, on the other hand, is defining multiple methods with the same name but different parameters within the same class. Python does not support traditional method overloading but can use default or variable-length arguments to achieve similar functionality.
3. Can you provide an example of polymorphism in Python?
Yes, see the examples provided in the "Detailed Explanation of Polymorphism" section where the speak
method is overridden in different subclasses.
4. How is polymorphism implemented in Python?
Polymorphism in Python is implemented through method overriding and duck typing. Python’s dynamic nature allows it to determine the method to call at runtime based on the object type.
5. What is the use of polymorphism in software design?
Polymorphism enhances code flexibility and reusability by allowing the same interface to interact with different underlying implementations. This makes it easier to extend and maintain code.
6. Explain the concept of method resolution order (MRO) and how it relates to polymorphism.
MRO determines the order in which methods are inherited from multiple base classes. It ensures that the correct method is called in the presence of multiple inheritance. Python uses the C3 linearization algorithm for MRO.
7. Can you override a method in Python? Provide an example.
Yes, methods can be overridden in Python. See the Dog
and Cat
classes in the "Detailed Explanation of Polymorphism" section for an example.
8. How do you achieve polymorphism with functions in Python?
You achieve polymorphism with functions by designing functions that can accept different types of objects as long as they share a common interface or method. See the make_animal_speak
function example.
9. Discuss the advantages of using polymorphism in a project.
Polymorphism improves code flexibility and scalability. It allows for writing more general code that can handle new types of objects without modification. This leads to easier maintenance and extension of code.
10. What is the difference between static and dynamic polymorphism?
Static polymorphism (method overloading) is resolved at compile time, whereas dynamic polymorphism (method overriding) is resolved at runtime. Python supports dynamic polymorphism but not static polymorphism.
Coding Questions and Solutions
1. Write a Python program that demonstrates method overriding with polymorphism.
Solution:
class Shape:
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius * self.radius
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side * self.side
shapes = [Circle(5), Square(4)]
for shape in shapes:
print(f'Area: {shape.area()}')
Output:
Area: 78.5
Area: 16
2. Explain how to achieve polymorphism in a scenario where you have multiple types of objects but need to perform the same operation on them.
Solution:
class Car:
def start_engine(self):
return "Car engine started"
class Bike:
def start_engine(self):
return "Bike engine started"
def start_vehicle_engine(vehicle):
print(vehicle.start_engine())
car = Car()
bike = Bike()
start_vehicle_engine(car)
start_vehicle_engine(bike)
Output:
Car engine started
Bike engine started
3. Create a base class Employee
with a method get_salary()
and derive FullTimeEmployee
and PartTimeEmployee
classes. Override the get_salary()
method in both derived classes.
Solution:
class Employee:
def get_salary(self):
return 0
class FullTimeEmployee(Employee):
def get_salary(self):
return 5000
class PartTimeEmployee(Employee):
def get_salary(self):
return 2000
employees = [FullTimeEmployee(), PartTimeEmployee()]
for emp in employees:
print(f'Salary: {emp.get_salary()}')
Output:
Salary: 5000
Salary: 2000
4. Implement a Shape
class with a method draw()
. Create Circle
and Rectangle
classes that override the draw()
method. Demonstrate polymorphism using these classes.
Solution:
class Shape:
def draw(self):
pass
class Circle(Shape):
def draw(self):
return "Drawing a circle"
class Rectangle(Shape):
def draw(self):
return "Drawing a rectangle"
shapes = [Circle(), Rectangle()]
for shape in shapes:
print(shape.draw())
Output:
Drawing a circle
Drawing a rectangle
5. Define a class Animal
with a method make_sound()
. Create subclasses Dog
, Cat
, and Bird
, each overriding make_sound()
. Write a function that takes an Animal
object and prints its sound.
Solution:
class Animal:
def make_sound(self):
return "Some sound"
class Dog(Animal):
def make_sound(self):
return "Bark"
class Cat(Animal):
def make_sound(self):
return "Meow"
class Bird(Animal):
def make_sound(self):
return "Chirp"
def print_animal_sound(animal):
print(animal.make_sound())
animals = [Dog(), Cat(), Bird()]
for animal in animals:
print_animal_sound(animal)
Output:
Bark
Meow
Chirp
6. Write a base class Transport
with a method move()
. Derive Car
and Boat
classes, each implementing move()
differently.
Solution:
class Transport:
def move(self):
pass
class Car(Transport):
def move(self):
return "Driving on road"
class Boat(Transport):
def move(self):
return "Sailing on water"
vehicles = [Car(), Boat()]
for vehicle in vehicles:
print(vehicle.move())
Output: ``
` Driving on road Sailing on water
**7. Create a base class `Vehicle` with a method `fuel_efficiency()`. Derive `ElectricCar` and `DieselTruck` classes, each providing a specific implementation for `fuel_efficiency()`.**
*Solution:*
```python
class Vehicle:
def fuel_efficiency(self):
pass
class ElectricCar(Vehicle):
def fuel_efficiency(self):
return "200 miles per charge"
class DieselTruck(Vehicle):
def fuel_efficiency(self):
return "15 miles per gallon"
vehicles = [ElectricCar(), DieselTruck()]
for vehicle in vehicles:
print(vehicle.fuel_efficiency())
Output:
200 miles per charge
15 miles per gallon
8. Implement a class Person
with a method greet()
. Derive Teacher
and Student
classes that override greet()
. Demonstrate polymorphism using these classes.
Solution:
class Person:
def greet(self):
return "Hello"
class Teacher(Person):
def greet(self):
return "Good morning, students"
class Student(Person):
def greet(self):
return "Hi, teacher"
people = [Teacher(), Student()]
for person in people:
print(person.greet())
Output:
Good morning, students
Hi, teacher
9. Define an interface Payment
with a method process_payment()
. Implement CreditCardPayment
and PayPalPayment
classes, each providing a specific implementation for process_payment()
.
Solution:
from abc import ABC, abstractmethod
class Payment(ABC):
@abstractmethod
def process_payment(self):
pass
class CreditCardPayment(Payment):
def process_payment(self):
return "Processing credit card payment"
class PayPalPayment(Payment):
def process_payment(self):
return "Processing PayPal payment"
payments = [CreditCardPayment(), PayPalPayment()]
for payment in payments:
print(payment.process_payment())
Output:
Processing credit card payment
Processing PayPal payment
10. Write a base class Document
with a method print_content()
. Create PDF
and Word
classes that override print_content()
. Demonstrate polymorphism with these document types.
Solution:
class Document:
def print_content(self):
pass
class PDF(Document):
def print_content(self):
return "Printing PDF content"
class Word(Document):
def print_content(self):
return "Printing Word content"
documents = [PDF(), Word()]
for document in documents:
print(document.print_content())
Output:
Printing PDF content
Printing Word content
11. Define a class Employee
with a method work()
. Derive Manager
and Developer
classes, each providing a specific implementation for work()
.
Solution:
class Employee:
def work(self):
return "Working"
class Manager(Employee):
def work(self):
return "Managing team"
class Developer(Employee):
def work(self):
return "Developing software"
employees = [Manager(), Developer()]
for employee in employees:
print(employee.work())
Output:
Managing team
Developing software
12. Implement a class Account
with a method calculate_interest()
. Derive SavingsAccount
and CheckingAccount
classes, each providing a specific implementation for calculate_interest()
.
Solution:
class Account:
def calculate_interest(self):
return 0
class SavingsAccount(Account):
def calculate_interest(self):
return "5% annual interest"
class CheckingAccount(Account):
def calculate_interest(self):
return "No interest"
accounts = [SavingsAccount(), CheckingAccount()]
for account in accounts:
print(account.calculate_interest())
Output:
5% annual interest
No interest
13. Create a base class Appliance
with a method turn_on()
. Derive WashingMachine
and Refrigerator
classes, each providing a specific implementation for turn_on()
.
Solution:
class Appliance:
def turn_on(self):
pass
class WashingMachine(Appliance):
def turn_on(self):
return "Washing machine is on"
class Refrigerator(Appliance):
def turn_on(self):
return "Refrigerator is on"
appliances = [WashingMachine(), Refrigerator()]
for appliance in appliances:
print(appliance.turn_on())
Output:
Washing machine is on
Refrigerator is on
14. Define a base class Report
with a method generate()
. Create AnnualReport
and MonthlyReport
classes that override generate()
.
Solution:
class Report:
def generate(self):
pass
class AnnualReport(Report):
def generate(self):
return "Generating annual report"
class MonthlyReport(Report):
def generate(self):
return "Generating monthly report"
reports = [AnnualReport(), MonthlyReport()]
for report in reports:
print(report.generate())
Output:
Generating annual report
Generating monthly report
15. Implement a class Shape
with a method calculate_area()
. Derive Triangle
and Rectangle
classes, each implementing calculate_area()
with specific formulas.
Solution:
class Shape:
def calculate_area(self):
pass
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def calculate_area(self):
return 0.5 * self.base * self.height
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def calculate_area(self):
return self.width * self.height
shapes = [Triangle(10, 5), Rectangle(4, 6)]
for shape in shapes:
print(f'Area: {shape.calculate_area()}')
Output:
Area: 25.0
Area: 24
Conclusion
Polymorphism is a powerful concept in object-oriented programming that allows different objects to respond to the same method in various ways. It enhances code flexibility and reusability, making it easier to extend and maintain. Understanding and implementing polymorphism effectively can lead to more adaptable and robust software designs.