Python 3.14 ·
✓ verified by execution on 2026-07-31
In 1994, the “Gang of Four” (GoF) published Design Patterns, detailing 23 solutions to common software design problems. Because they used C++ and Smalltalk, many of these patterns rely on heavy class hierarchies and abstract interfaces.
In Python, however, we have first-class functions, decorators, and dynamic typing. Because of this, many GoF patterns collapse into just a few lines of code, or disappear entirely. Let’s look at the Pythonic alternatives.
The Strategy Pattern (First-Class Functions)
The Strategy pattern allows you to switch out algorithms at runtime. In Java, this requires defining an interface Strategy, creating multiple concrete classes that implement that interface, and passing instances of those classes to a context.
In Python, functions are first-class. You can just pass a function!
python · visualize
# The classic OOP way (Bloated)class AbstractStrategy: def execute(self, data): passclass MultiplyStrategy(AbstractStrategy): def execute(self, data): return [x * 2 for x in data]# The Pythonic Way (Simple!)def multiply_strategy(data): return [x * 2 for x in data]def execute(data, strategy_func): return strategy_func(data)print(execute([1, 2, 3], multiply_strategy))
[2, 4, 6]
The Factory Pattern (Dictionaries)
Factories abstract away the instantiation of objects. Instead of building massive Factory and AbstractFactory classes, Python leverages the fact that classes themselves are callable objects. You can store them in a dictionary!
python
class Dog: def speak(self): return "Woof!"class Cat: def speak(self): return "Meow!"# A perfect Pythonic Factoryanimal_factory = { "dog": Dog, "cat": Cat}def create_animal(animal_type): if animal_type not in animal_factory: raise ValueError("Unknown animal") # Fetch the class object and call it () to instantiate return animal_factory[animal_type]()pet = create_animal("dog")print(pet.speak())
Output
Woof!
Your output
The Registry Pattern (Decorators)
What if you don’t want to hardcode all the classes in your dictionary factory? What if users add their own classes in different files? Enter the Registry Pattern, elegantly solved via decorators.
python
_registry = {}# A decorator that adds the class to our dictionarydef register(name): def decorator(cls_or_func): _registry[name] = cls_or_func return cls_or_func return decorator@register("bird")class Bird: def speak(self): return "Tweet!"@register("fish")class Fish: def speak(self): return "Blub"print(f"Registered animals: {list(_registry.keys())}")print(_registry["bird"]().speak())
Output
Registered animals: ['bird', 'fish']
Tweet!
Your output
The Observer Pattern (Callback Lists)
The Observer pattern notifies multiple components when an event happens. Instead of making an Observer base class, Python simply uses a list of callback functions.
python
class EventDispatcher: def __init__(self): self._callbacks = [] def subscribe(self, callback): self._callbacks.append(callback) def trigger_event(self, data): for callback in self._callbacks: callback(data)def logger(data): print(f"Log: {data}")def alerter(data): print(f"Alert: {data}")dispatcher = EventDispatcher()dispatcher.subscribe(logger)dispatcher.subscribe(alerter)dispatcher.trigger_event("Server started")
Output
Log: Server started
Alert: Server started
Your output
The Singleton Pattern (Modules)
Many developers tie themselves in knots trying to override __new__ or write metaclasses to ensure a class only instantiates once.
The official, most Pythonic way to implement a Singleton? Just use a module.
When you import my_database in Python, the interpreter loads it exactly once and caches it in sys.modules. Any subsequent imports across your entire app just return a reference to that exact same cached module. Variables inside that module are naturally Singletons!
Check yourself
What is the most Pythonic way to implement the Singleton pattern?
Reveal answer
Defining variables and functions at the module level and importing them. — Python's import system guarantees that a module is initialized exactly once and cached in `sys.modules`. Simply writing your logic at the module level natively acts as a thread-safe Singleton without any boilerplate.
In Python, how is the Strategy pattern usually simplified?
Reveal answer
By passing a first-class function directly as an argument, bypassing the need for interface classes. — Because Python supports first-class functions, you can pass functions directly into other functions. This eliminates the need for the bulky Strategy class hierarchies common in Java or C++.
Why is the Abstract Factory pattern rarely used in standard Python?
Reveal answer
A simple dictionary mapping string names to class objects is usually sufficient. — Classes in Python are first-class objects (they can be passed around and executed just like functions). A simple dictionary mapping keys to classes creates a perfect factory with virtually zero boilerplate.
Challenges
Challenge 1 +100 XP
Implement the Strategy pattern using first-class functions. Create a function 'sort_by_length' and 'sort_by_alphabet'. Write an 'execute_sort' function that accepts a list and a strategy function, and returns the sorted list.
python
Test 1 — expects "['cat', 'apple', 'banana']\n['apple', 'banana', 'cat']\n"
Create a dictionary '_registry'. Write a decorator function 'register_handler' that takes a string name, adds the decorated function to '_registry' under that name, and returns the function unmodified.