Python Polymorphism Examples
Short, runnable programs that show python polymorphism and duck typing in action. Read the explanation, press Run, then change the code and try your own ideas. New to the topic? Start with the Python Polymorphism and Duck Typing lesson.
1for loops and in work on anything iterable
A for loop does not care whether it receives a string, a list, a dictionary or a range. Each of them knows how to hand out its items, and in works across all of them too. That is polymorphism built into the language.
things = ["cat", [10, 20], {"a": 1}, range(3)]
for thing in things:
print(type(thing).__name__, list(thing))
print("a" in "cat", 20 in [10, 20], "a" in {"a": 1}, 2 in range(3))Expected outputstr ['c', 'a', 't']
list [10, 20]
dict ['a']
range [0, 1, 2]
True True True True
2A parent that calls the child's version
Exporter.export() is written once and calls self.format_row(). Each child overrides only format_row, and Python picks the right one because self is the child object. The base class gets a sensible default.
class Exporter:
def export(self, rows):
return "\n".join(self.format_row(row) for row in rows)
def format_row(self, row):
return " ".join(str(cell) for cell in row)
class CsvExporter(Exporter):
def format_row(self, row):
return ",".join(str(cell) for cell in row)
class MarkdownExporter(Exporter):
def format_row(self, row):
return "| " + " | ".join(str(cell) for cell in row) + " |"
rows = [("Asha", 91), ("Ben", 78)]
for exporter in [Exporter(), CsvExporter(), MarkdownExporter()]:
print(exporter.export(rows))Expected outputAsha 91
Ben 78
Asha,91
Ben,78
| Asha | 91 |
| Ben | 78 |
3Replace an isinstance() chain with a method
The chain handles two file types and quietly returns None for the third. Asking each object for its own preview() works for all three, and for any class you add later.
class TextFile:
def preview(self):
return "first 3 lines of text"
class ImageFile:
def preview(self):
return "small thumbnail"
class PdfFile:
def preview(self):
return "page 1 as an image"
def preview_with_chain(item):
if isinstance(item, TextFile):
return "text: " + item.preview()
elif isinstance(item, ImageFile):
return "image: " + item.preview()
files = [TextFile(), ImageFile(), PdfFile()]
print([preview_with_chain(f) for f in files])
print([f.preview() for f in files])Expected output['text: first 3 lines of text', 'image: small thumbnail', None]
['first 3 lines of text', 'small thumbnail', 'page 1 as an image']
4A stand-in object for testing
Duck typing makes it easy to swap a real dependency for a test double. welcome() only needs something with a send() method, so a FakeMailer that records messages works without sending anything.
class FakeMailer:
def __init__(self):
self.outbox = []
def send(self, to, text):
self.outbox.append((to, text))
class ConsoleMailer:
def send(self, to, text):
print(f"[console] {to}: {text}")
def welcome(name, address, mailer):
mailer.send(address, f"Welcome, {name}!")
welcome("Asha", "asha@example.com", ConsoleMailer())
fake = FakeMailer()
welcome("Ben", "ben@example.com", fake)
welcome("Chen", "chen@example.com", fake)
print(fake.outbox)Expected output[console] asha@example.com: Welcome, Asha!
[('ben@example.com', 'Welcome, Ben!'), ('chen@example.com', 'Welcome, Chen!')]
5Optional methods with getattr()
Not every resource needs clean-up. getattr(obj, name, default) looks the method up safely, and callable() makes sure what you found can be called. Objects without close() are simply skipped.
class Database:
def close(self):
print("database closed")
class Logger:
pass # nothing to close
class Cache:
def close(self):
print("cache cleared")
def shutdown(resources):
for resource in resources:
close = getattr(resource, "close", None)
if callable(close):
close()
else:
print(type(resource).__name__, "needs no cleanup")
shutdown([Database(), Logger(), Cache()])Expected outputdatabase closed
Logger needs no cleanup
cache cleared
Practise next
Python Polymorphism and Duck Typing exercises → Back to the lesson
Python Dunder (Magic) Methods examplesPython Inheritance examplesPython Abstract Classes (ABC) examples