VOOZH about

URL: https://www.codecademy.com/article/understanding-polymorphism-in-python

⇱ Understanding Polymorphism in Python (With Examples) | Codecademy


Skip to Content
Articles

Understanding Polymorphism in Python (With Examples)

What is polymorphism in Python?

Polymorphism in Python refers to the ability of different objects to respond to the same method or function call in ways specific to their individual types. The term comes from Greek words “poly” (many) and “morphos” (forms), literally meaning “many forms.” Polymorphism is a core concept in object-oriented programming (OOP) that allows programmers to use a single interface with different underlying forms.

In Python, polymorphism enables you to write more flexible and reusable code by allowing objects of different classes to be treated as objects of a common superclass. This fundamental OOP principle makes your code more modular, extensible, and easier to maintain.

Let’s explore how polymorphism works in Python with a simple example:

classBird:
defsound(self):
return"Tweet"
classDog:
defsound(self):
return"Bark"
defmake_sound(animal):
print(animal.sound())
# Create objects
bird = Bird()
dog = Dog()
# Same function call, different behaviors
make_sound(bird)# Output: Tweet
make_sound(dog)# Output: Bark
Copy to clipboard
Copy to clipboard

In this example, both Bird and Dog classes have a method called sound(), but each implementation returns a different result. The make_sound() function accepts any object that has a sound() method, demonstrating polymorphism in action.

Types of polymorphism in Python

Python supports several types of polymorphism. Understanding each type will help you leverage polymorphism effectively in your code.

1. Duck typing

Duck typing is a concept related to dynamic typing where the type or class of an object is less important than the methods it defines. The name comes from the saying: “If it walks like a duck and quacks like a duck, then it probably is a duck.”

classDuck:
defswim(self):
return"Duck swimming"
deffly(self):
return"Duck flying"
classAirplane:
deffly(self):
return"Airplane flying"
deffly_test(entity):
print(entity.fly())
# Create objects
duck = Duck()
airplane = Airplane()
# Same function works with different objects
fly_test(duck)# Output: Duck flying
fly_test(airplane)# Output: Airplane flying
Copy to clipboard
Copy to clipboard

In this example, the fly_test() function works with any object that has a fly() method, regardless of its type. This is a typical example of duck typing.

2. Method overriding

Method overriding occurs when a subclass provides a specific implementation of a method that is already defined in its parent class. This is one of the most common forms of polymorphism in Python.

classAnimal:
defspeak(self):
return"Animal makes a sound"
classCat(Animal):
defspeak(self):
return"Meow"
classCow(Animal):
defspeak(self):
return"Moo"
# Create objects
animal = Animal()
cat = Cat()
cow = Cow()
# Same method name, different behaviors
print(animal.speak())# Output: Animal makes a sound
print(cat.speak())# Output: Meow
print(cow.speak())# Output: Moo
Copy to clipboard
Copy to clipboard

In this example, both Cat and Cow classes override the speak() method of their parent class Animal.

3. Operator overloading

Operator overloading is a feature in Python that allows the same operator to have different meanings according to the context. For instance, the + operator performs arithmetic addition on numbers but concatenation on strings.

classPoint:
def__init__(self, x, y):
self.x = x
self.y = y
def__add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def__str__(self):
returnf"Point({self.x}, {self.y})"
# Create Point objects
p1 = Point(1,2)
p2 = Point(3,4)
# Using the + operator on Point objects
p3 = p1 + p2
print(p3)# Output: Point(4, 6)
Copy to clipboard
Copy to clipboard

In this example, we’ve overloaded the + operator for the Point class by implementing the __add__ special method.

4. Function and method overloading

Unlike some other OOP languages, Python doesn’t support traditional function or method overloading, where multiple methods with the same name but different parameters are defined. However, Python achieves similar functionality through default parameters and variable-length arguments.

defcalculate_area(length, width=None):
if width isNone:
return length * length
return length * width
# Using the function with different arguments
print(calculate_area(5))# Output: 25 (square)
print(calculate_area(4,6))# Output: 24 (rectangle)
Copy to clipboard
Copy to clipboard

This example shows how a single function can handle different types of inputs, demonstrating polymorphic behavior.

Examples of polymorphism in Python

Let’s look at some more practical examples of polymorphism in Python to better understand how it works in real-world scenarios.

Example 1: Polymorphism with class methods

classShape:
defarea(self):
pass
defperimeter(self):
pass
classRectangle(Shape):
def__init__(self, length, width):
self.length = length
self.width = width
defarea(self):
return self.length * self.width
defperimeter(self):
return2*(self.length + self.width)
classCircle(Shape):
def__init__(self, radius):
self.radius = radius
defarea(self):
return3.14* self.radius * self.radius
defperimeter(self):
return2*3.14* self.radius
# Create shape objects
rectangle = Rectangle(5,4)
circle = Circle(3)
# Process different shapes using the same methods
shapes =[rectangle, circle]
for shape in shapes:
print(f"Area: {shape.area()}")
print(f"Perimeter: {shape.perimeter()}")
Copy to clipboard
Copy to clipboard

In this example, both Rectangle and Circle inherit from Shape and override its methods. We can process different shapes with the same code, demonstrating polymorphism.

Example 2: Polymorphism with built-in functions

Python’s built-in functions like len() and str() also demonstrate polymorphism. They work with different types of objects:

# The len() function with different data types
print(len("Hello"))# Output: 5
print(len([1,2,3]))# Output: 3
print(len({"name":"John","age":30}))# Output: 2
# The str() function with different data types
print(str(123))# Output: "123"
print(str([1,2,3]))# Output: "[1, 2, 3]"
print(str({"a":1}))# Output: "{'a': 1}"
Copy to clipboard
Copy to clipboard

Here, len() and str() behave differently based on the type of object they’re called with, demonstrating polymorphic behavior.

Why use polymorphism in Python

Polymorphism offers several benefits that make it a valuable tool in Python programming:

  1. Code Reusability: Polymorphism allows you to reuse code by defining methods in a base class that subclasses can override according to their specific needs.

  2. Flexibility: It provides flexibility to use objects of different types through a common interface, making your code more adaptable to changes.

  3. Abstraction: Polymorphism helps in hiding the complex implementation details while exposing a simple interface to the users of your code.

  4. Maintainability: By promoting code organization and reusability, polymorphism makes your code easier to maintain and extend.

  5. Cleaner Code: It reduces conditional statements and type checks, resulting in cleaner and more readable code.

Practical applications of polymorphism

Polymorphism isn’t just a theoretical concept; it has numerous practical applications in real-world Python programming:

Application 1: GUI programming

In graphical user interface (GUI) programming, different UI elements (buttons, text boxes, etc.) may respond differently to the same events (clicks, keypresses):

classButton:
defclick(self):
return"Button clicked"
classCheckbox:
defclick(self):
return"Checkbox toggled"
defhandle_click(ui_element):
print(ui_element.click())
# Create UI elements
button = Button()
checkbox = Checkbox()
# Handle clicks on different elements
handle_click(button)# Output: Button clicked
handle_click(checkbox)# Output: Checkbox toggled
Copy to clipboard
Copy to clipboard

Application 2: database interfaces

Different database systems can be accessed through a common interface using polymorphism:

classDatabase:
defconnect(self):
pass
defexecute_query(self, query):
pass
classMySQLDatabase(Database):
defconnect(self):
return"Connected to MySQL"
defexecute_query(self, query):
returnf"Executing in MySQL: {query}"
classPostgreSQLDatabase(Database):
defconnect(self):
return"Connected to PostgreSQL"
defexecute_query(self, query):
returnf"Executing in PostgreSQL: {query}"
defrun_query(database, query):
print(database.connect())
print(database.execute_query(query))
# Create database objects
mysql = MySQLDatabase()
postgres = PostgreSQLDatabase()
# Run the same query on different databases
run_query(mysql,"SELECT * FROM users")
run_query(postgres,"SELECT * FROM users")
Copy to clipboard
Copy to clipboard

Application 3: file handling

Polymorphism can be used to handle different file types with a uniform interface:

classFileHandler:
defopen(self, filename):
pass
defprocess(self, data):
pass
classTextFileHandler(FileHandler):
defopen(self, filename):
returnf"Opening text file: {filename}"
defprocess(self, data):
returnf"Processing text data: {data}"
classImageFileHandler(FileHandler):
defopen(self, filename):
returnf"Opening image file: {filename}"
defprocess(self, data):
returnf"Processing image data: {data}"
defhandle_file(handler, filename, data):
print(handler.open(filename))
print(handler.process(data))
# Create file handlers
text_handler = TextFileHandler()
image_handler = ImageFileHandler()
# Handle different file types
handle_file(text_handler,"document.txt","Hello World")
handle_file(image_handler,"photo.jpg","Binary data")
Copy to clipboard
Copy to clipboard

Conclusion

Polymorphism in Python is a powerful concept that allows for more flexible, reusable, and maintainable code. By understanding and applying the different types of polymorphism — duck typing, method overriding, operator overloading, and function overloading — you can write more elegant and efficient Python programs.

To deepen your understanding of object-oriented programming concepts like polymorphism, check out Codecademy’s Learn Python 3 course, which covers these topics in depth with interactive exercises.

Frequently Asked Questions

1. What is the difference between polymorphism and inheritance in Python?

While both are important OOP concepts, they serve different purposes. Inheritance is a mechanism where a class inherits attributes and methods from another class. It promotes code reuse and establishes a parent-child relationship between classes. Polymorphism, on the other hand, is the ability to use a common interface for different types of objects. Polymorphism often works with inheritance but can also exist independently (as in duck typing).

2. What is the role of the isinstance() function in polymorphism?

The isinstance() function can be used to check if an object is an instance of a specific class or its subclasses. While it’s sometimes useful, relying too heavily on isinstance() checks can defeat the purpose of polymorphism, which aims to treat objects based on their behavior rather than their types. Duck typing is often a more Pythonic approach.

3. Can I use polymorphism with Python’s built-in data types?

Yes, Python’s built-in types like lists, dictionaries, and strings already exhibit polymorphic behavior with operations like iteration, indexing, and methods like append(), update(), etc. You can also extend built-in types to add custom polymorphic behavior.

4. Is polymorphism only useful in large applications?

While polymorphism shows its full potential in larger applications, it can be beneficial even in smaller projects. By promoting cleaner, more organized code, polymorphism makes your code more maintainable and easier to extend, regardless of the project size.

Codecademy Team

'The Codecademy Team, composed of experienced educators and tech experts, is dedicated to making tech skills accessible to all. We empower learners worldwide with expert-reviewed content that develops and enhances the technical skills needed to advance and succeed in their careers.'

Meet the full team

Learn more on Codecademy