B3.2.2 Construct code to model polymorphism and its various forms, such as method overriding. (HL only)

B3.2.2 Construct code to model polymorphism and its various forms, such as method overriding. 
• The principle of polymorphism and how it contributes to code flexibility and reusability 
• How to implement dynamic polymorphic behaviour through mechanisms like method overriding 
• How to apply static polymorphic behaviour to maximize code efficiency

The big idea

Polymorphism means “many forms.”
In object-oriented programming, it allows different classes to be treated the same way through a common interface, even if they behave differently.

The benefit? We can write code that works with different object types without knowing their exact classes in advance — making programs flexible, reusable, and easier to extend.

Why polymorphism matters

  • Flexibility: One block of code can handle many object types.
  • Reusability: You can write general-purpose functions and methods.
  • Extensibility: Adding new behavior often means just adding a new class that follows the existing pattern.

 

1. Dynamic polymorphism (runtime polymorphism)

In Python, dynamic polymorphism is achieved through method overriding — a subclass provides a specific implementation for a method already defined in its superclass.

Example:

class Animal:
    def speak(self):
        return "Some generic sound"

class Dog(Animal):
    def speak(self):
        return "Bark"

class Cat(Animal):
    def speak(self):
        return "Meow"

# Runtime decision
animals = [Dog(), Cat(), Animal()]
for animal in animals:
    print(animal.speak())

Output:

Bark
Meow
Some generic sound

Key points:

  • The speak() method name is the same across all classes.
  • At runtime, Python decides which version to call based on the object type.
  • This allows one loop to handle different animal types without type checks.

 

2. Static polymorphism (compile-time–style behavior in Python)

Python doesn’t have true compile-time polymorphism like Java or C++ (where method overloading is resolved at compile time). Instead, we can mimic static polymorphism by:

  • Using default parameters
  • Using *args and **kwargs to accept variable arguments
  • Type checking inside a single method

Example:

class MathUtils:
    def add(self, a, b=0, c=0):
        return a + b + c

math = MathUtils()
print(math.add(2, 3))      # Two parameters
print(math.add(2, 3, 4))   # Three parameters

Output:

5
9

Here, the same method name handles different numbers of arguments. The decision on how many values to sum is made in the function body, which Python processes at runtime — but the effect is similar to static polymorphism in other languages.

 

3. Combining both in a real scenario

Imagine a payment system:

  • Dynamic polymorphism: Different payment types override a process_payment() method.
  • Static polymorphism (Python-style): The same method name accepts different argument formats for convenience.
class Payment:
    def process_payment(self, amount):
        raise NotImplementedError

class CreditCardPayment(Payment):
    def process_payment(self, amount):
        return f"Processing credit card payment of ${amount}"

class PayPalPayment(Payment):
    def process_payment(self, amount):
        return f"Processing PayPal payment of ${amount}"

class PaymentProcessor:
    def refund(self, amount, reason=None):
        if reason:
            return f"Refunded ${amount} due to: {reason}"
        return f"Refunded ${amount}"

# Dynamic polymorphism
payments = [CreditCardPayment(), PayPalPayment()]
for p in payments:
    print(p.process_payment(100))

# Static polymorphism effect
processor = PaymentProcessor()
print(processor.refund(50))
print(processor.refund(50, "Product defect"))

 

Best practices

  • Use method overriding for dynamic polymorphism when subclass behavior differs.
  • Use flexible parameter handling for Python’s style of static polymorphism.
  • Keep method names consistent across related classes for maximum interchangeability.
  • Avoid unnecessary type checks — rely on duck typing and clear method contracts.