Python Polymorphism · Exercises
Object-Oriented Python

Python Polymorphism Exercises

4 exercises that build on the Python Polymorphism and Duck Typing lesson, from easy to hard. Each one is checked in your browser when you press Check. Stuck? Use the hint before peeking at the solution.

What this lesson covers: Polymorphism means different kinds of objects respond to the same method call in their own way, and in Python duck typing means an object only needs to have the right method, not the right parent class, to be used. By the end you can write one function or loop that works with many different objects, use overriding and duck typing to get different behaviour from the same call, spot polymorphism in built-ins like len() and +, avoid long isinstance() chains, and check for a method with hasattr() or try/except. You will practise: Broadcast to any sender; Predict the headers; Find the skipped channel; Pick the cheapest payment method.

0 / 4 completed

Python Polymorphism practice exercises

1. Broadcast to any sender

Write code Easy

EmailSender is given. Do two things:

  1. Write a class SmsSender with a method send(message) that returns "SMS: <message>".
  2. Write broadcast(senders, message) that returns a list with the result of send(message) for every object in senders, in order. It must work for any object that has a send method, even one that is not one of your classes.
Your code
class EmailSender:
    def send(self, message):
        return f"Email: {message}"

# write class SmsSender here


def broadcast(senders, message):
    pass


print(broadcast([EmailSender()], "Hello"))

2. Predict the headers

Predict the output Medium

header() is only written in Report and Memo, but it calls self.title(). Type exactly what the program prints.

Read this code
class Report:
    def title(self):
        return "Report"

    def header(self):
        return f"== {self.title()} =="

class SalesReport(Report):
    def title(self):
        return "Sales " + super().title()

class Memo:
    def header(self):
        return "-- memo --"

for doc in [Report(), SalesReport(), Memo()]:
    print(doc.header())
print(isinstance(Memo(), Report), hasattr(Memo(), "title"))

3. Find the skipped channel

Fix the bug Medium

notify_all is supposed to send the message through every channel, but the push notification is quietly skipped. The output should end with push: Hi. Fix the class (leave notify_all alone) so that all three channels are used.

Your code
class EmailChannel:
    def send(self, message):
        return f"email: {message}"

class SmsChannel:
    def send(self, message):
        return f"sms: {message}"

class PushChannel:
    def send_push(self, message):
        return f"push: {message}"

def notify_all(channels, message):
    results = []
    for channel in channels:
        try:
            results.append(channel.send(message))
        except AttributeError:
            results.append("skipped " + type(channel).__name__)
    return results

for line in notify_all([EmailChannel(), SmsChannel(), PushChannel()], "Hi"):
    print(line)

4. Pick the cheapest payment method

Write code Hard

Build a tiny payment system:

  1. PaymentMethod has fee(amount) returning 0, and total(amount) returning amount plus self.fee(amount).
  2. CreditCard inherits from PaymentMethod and charges a fee of 3% of the amount.
  3. BankTransfer inherits from PaymentMethod and charges a flat fee of 0.5.
  4. cheapest(methods, amount) returns the object from methods with the lowest total(amount); on a tie the first one wins. It must work for any object that has a total(amount) method, even one that does not inherit from PaymentMethod.
Your code
class PaymentMethod:
    pass          # give it fee(amount) and total(amount)

# class CreditCard(PaymentMethod): 3% fee
# class BankTransfer(PaymentMethod): flat fee of 0.5


def cheapest(methods, amount):
    pass


print("write the classes and cheapest()")

Next lessonPython Multiple Inheritance and MRO

More Python Polymorphism and Duck Typing examples · All Python exercises