Menu
Courses / python advanced / Design Patterns in Python

Design Patterns in Python

09 / 10 Part of python advanced




 

    🎓 Advanced · Topic 09
 

 


    Design Patterns in Python
 


 


    Reusable solutions to common software design problems. Learn the most practical patterns — Singleton, Factory, Observer, Strategy, and more — implemented idiomatically in Python.
 


 

    ⏱ ~65 min
    🔴 Advanced
    🏛️ Architecture
 


 
 

   

     
     

Pattern Categories


   

   

     

        Creational
       

How objects are created — Singleton, Factory, Builder, Prototype


     

     

        Structural
       

How objects are composed — Decorator, Adapter, Proxy, Facade


     

     

        Behavioural
       

How objects communicate — Observer, Strategy, Command, Iterator


     

   

 


 
 

   

     
     

Factory Pattern


   

   

A factory creates objects without exposing instantiation logic. In Python, a simple dict-dispatch factory is idiomatic and avoids lengthy if/elif chains.


   

     

        factory.py
     

     
class JSONSerializer:
    def serialize(self, data): return f"JSON:{data}"

class XMLSerializer:
    def serialize(self, data): return f"<data>{data}</data>"

class CSVSerializer:
    def serialize(self, data): return f"csv,{data}"

# Dict-dispatch factory — easily extensible
_SERIALIZERS = {
    "json": JSONSerializer,
    "xml"XMLSerializer,
    "csv"CSVSerializer,
}

def get_serializer(fmt: str):
    try:
        return _SERIALIZERS[fmt]()
    except KeyError:
        raise ValueError(f"Unknown format: {fmt}")

s = get_serializer("json")
print(s.serialize("hello"))  # JSON:hello

   

 


 
 

   

     
     

Observer Pattern


   

   

Lets objects subscribe to events. When the subject changes state, all observers are notified automatically — the foundation of event-driven systems.


   

     

        observer.py
     

     
from __future__ import annotations
from typing import Callable

class EventEmitter:
    def __init__(self):
        self._handlers: dict[str, list[Callable]] = {}

    def on(self, event: str, handler: Callable):
        self._handlers.setdefault(event, []).append(handler)

    def emit(self, event: str, *args, **kwargs):
        for h in self._handlers.get(event, []):
            h(*args, **kwargs)

bus = EventEmitter()
bus.on("login", lambda u: print(f"Welcome {u}"))
bus.on("login", lambda u: print(f"Logging: {u} logged in"))
bus.emit("login", "Alice")

   

 


 
 

   

     
     

Strategy Pattern


   

   

Define a family of algorithms and make them interchangeable. In Python, functions are first-class, so a strategy is simply a callable — no abstract class required.


   

     

        strategy.py
     

     
from typing import Callable

def sort_by_price(items):   return sorted(items, key=lambda x: x["price"])
def sort_by_name(items):    return sorted(items, key=lambda x: x["name"])
def sort_by_rating(items):  return sorted(items, key=lambda x: -x["rating"])

class ProductListing:
    def __init__(self, strategy: Callable):
        self.strategy = strategy

    def display(self, products):
        return self.strategy(products)

listing = ProductListing(sort_by_price)
listing.strategy = sort_by_rating   # swap at runtime