</> Code Editor { } Code Formatter

Python Polymorphism Exercises


1/20

Python Polymorphism Practice Questions

Correct
0%

In Python, the built-in len() function is a polymorphic interface. When you call len(obj), Python internally attempts to call obj.__len__(). Which of the following is a strict requirement imposed by the Python interpreter on the __len__ method?


Python's polymorphism through "Protocols" relies on specific contracts. The len() function is a prime example of this.

  • The Contract: Python expects __len__ to behave predictably. Because "length" is logically a count of elements, it must be a whole number and cannot be negative.
  • The Error: If you try to return -1 or 5.5, Python won't just "deal with it." It will raise a TypeError (for non-integers) or a ValueError (for negative integers) at the moment len() is called.
  • Protocol over Type: Note that obj does not have to be a list or a string. As long as it has a valid __len__, it is polymorphic with all other "sized" objects in Python.
class MySizedObject:
    def __len__(self):
        return -1

obj = MySizedObject()
# print(len(obj))  # This will raise: ValueError: __len__() should return >= 0

Key Takeaway: Polymorphism in Python requires more than just matching method names; you must also adhere to the expected return types and logic constraints of the protocol.

Quick Recap of Python Polymorphism Concepts

If you are not clear on the concepts of Polymorphism, you can quickly review them here before practicing the exercises. This recap highlights the essential points and logic to help you solve problems confidently.

Understanding Polymorphism in Python

At its heart, polymorphism is about flexibility. The term literally means "many forms," and in Python, it allows different types of objects to be handled through the same interface. Imagine having a universal remote; you press the "Power" button, and whether it’s a TV, a soundbar, or a projector, each device responds in its own way. That is polymorphism in action.

Polymorphism with Class Methods

The simplest way to see polymorphism is when different classes share the same method names. This allows us to group diverse objects together and call their methods in a single loop without worrying about which specific class each object belongs to.

class SatelliteBroadcaster:
    def transmit(self):
        return "Sending encoded signal via orbital relay."

class FiberBroadcaster:
    def transmit(self):
        return "Sending light pulses through underground cables."

class MicrowaveRelay:
    def transmit(self):
        return "Beaming high-frequency waves to the next tower."

# We treat different objects as a single group
telecom_nodes = [SatelliteBroadcaster(), FiberBroadcaster(), MicrowaveRelay()]

for node in telecom_nodes:
    print(node.transmit())

Polymorphism and Inheritance

When we combine inheritance with polymorphism, we get Method Overriding. A child class can take a method from its parent and give it a unique "spin." This ensures that while the child fits the general category of the parent, it retains its specific behavior.

FeatureDescription
Method OverridingReplacing a parent's method with a specific version in the child class.
Method Resolution Order (MRO)The internal path Python takes to find which version of a method to run.
Abstract Base ClassesUsing the abc module to force child classes to implement specific methods.
class IndustrialMachine:
    def startup_sequence(self):
        return "General system check initiated."

class HydraulicPress(IndustrialMachine):
    def startup_sequence(self):
        return "Pressurizing fluid lines and checking valve seals."

class RoboticArm(IndustrialMachine):
    def startup_sequence(self):
        return "Calibrating multi-axis joints and optical sensors."

def activate_unit(machine):
    # This function works for any IndustrialMachine subclass
    print(machine.startup_sequence())

activate_unit(HydraulicPress())
activate_unit(RoboticArm())

The Magic of Duck Typing in Python

Python is famous for "Duck Typing." The rule is: “If it walks like a duck and quacks like a duck, it’s a duck.” In coding terms, Python doesn't care about the object's actual class; it only cares if the object has the method we are trying to call. This makes Python incredibly dynamic and readable.

class CipherEngine:
    def process_data(self, payload):
        return f"Encrypted: {payload[::-1]}"

class CompressionEngine:
    def process_data(self, payload):
        return f"Compressed: {len(payload)} bytes"

def run_pipeline(engine, raw_input):
    # 'engine' doesn't need to inherit from anything specific
    # It just needs a 'process_data' method.
    print(engine.process_data(raw_input))

run_pipeline(CipherEngine(), "SECURE_DATA")

Python Polymorphism in Built-in Tools

You’ve likely been using polymorphism without even realizing it. Python’s operators and functions are designed to handle different data types differently.

AspectPolymorphic Behavior
The + OperatorAdds numbers but merges strings and lists.
The len() FunctionCounts characters in a string, items in a list, or keys in a dictionary.
The * OperatorMultiplies integers but repeats sequences (like strings).
# Polymorphic '+' operator
print(150 + 350)          # Addition
print("Error" + "_404")   # Concatenation

# Polymorphic len() function
print(len("Solviyo"))     # Length of string
print(len([10, 20, 30]))  # Length of list

Operator Overloading in Python

You can actually teach Python’s operators how to handle your custom objects. By using "Dunder" (Double Under) methods, you make your classes behave like native Python types.

Dunder MethodOperator
__add__+
__mul__*
__str__print() or str()
class DataPacket:
    def __init__(self, size):
        self.size = size

    def __add__(self, other):
        # Allows us to 'add' two DataPacket objects together
        return DataPacket(self.size + other.size)

    def __str__(self):
        return f"Packet Size: {self.size}KB"

p1 = DataPacket(100)
p2 = DataPacket(250)
print(p1 + p2)

Best Practices & Summary

  • Uniform Interfaces: Always keep the method names and arguments the same across polymorphic classes to avoid unexpected errors.
  • Avoid Over-Engineering: Don't use inheritance-based polymorphism if simple Duck Typing or functions will do the trick.
  • Documentation: Clearly state what methods an object is expected to have if you are using Duck Typing in your functions.
ConceptKey Takeaway
DefinitionAllows different classes to share the same interface.
OverridingLets subclasses customize inherited methods.
Duck TypingPrioritizes "behavior" over "class type."
Dunder methodsAllow custom objects to use standard Python operators.


About This Exercise: Python – Polymorphism

Ever wondered why the plus operator can add two integers but also join two strings? That’s polymorphism in action. In Python, polymorphism is about providing a single interface for different data types. It allows us to write functions that don’t care exactly what object they’re holding, as long as that object can perform the requested action. We’ve designed these Python exercises to move you past basic "animal sounds" examples and into the logic powering professional frameworks. You’ll tackle MCQs and coding practice that force you to think about how objects interact when they share a common interface but behave differently under the hood.

We focus heavily on the "Pythonic" approach. Unlike languages limited to strict inheritance, Python offers the freedom of Duck Typing—if it walks and quacks like a duck, it’s a duck. These exercises help you master this flexibility without letting your code turn into a chaotic mess. You’ll learn to write "type-agnostic" functions that make your software far more resilient to change.

What You Will Learn

This section turns theory into muscle memory. Through our structured Python exercises with answers, you will master:

  • Method Overriding: How child classes redefine parent methods to provide specific behavior.
  • Duck Typing: Writing code that focuses on what an object can do rather than its class.
  • Polymorphism in Functions: Creating generic logic that processes various object types without if-else chains.
  • Operator Overloading: Using special methods like __add__ to make custom objects behave like built-in types.
  • Abstract Interfaces: Enforcing a consistent API across large-scale applications.

Why This Topic Matters

Without polymorphism, code becomes a brittle web of type-checks. Imagine a drawing app checking if a shape is a Circle or Square every time it renders. That’s a maintenance nightmare. With polymorphism, you just call draw(), and the object handles the rest. This decouples logic from implementation, which is vital for scalability. In a professional environment, this leads to cleaner code, better readability, and easier reusability for other developers on your team.

Start Practicing

Ready to level up your OOP design? Our Python exercises come with detailed explanations and answers to help you bridge the gap between theory and code. We break down the internal execution so you can apply these patterns immediately. If you're unsure about overriding versus overloading, check our "Quick Recap" section for a fast refresh. Let’s see if you can handle the dynamic nature of Python polymorphism.