Implementation of Common Design Patterns in Python

Roman Latyshenko


Design patterns in Python

In software development, design patterns are a proven solution to a common problem in a specific context. 

Their main goal is to show us good ways to program things and explain why other options won’t work. 

Using common design patterns, you can:

  • Speed up the development process;
  • Reduce the number of lines of code;
  • Make sure your code is well-designed;
  • Anticipate future problems arising from small issues.

Design patterns can considerably improve the life of a software developer disregarding the programming language (s)he uses. 

I mainly work with Python/ Django, so here is my list of top patterns in Python I use daily in my job.


Behavioral patterns


Iterator allows traversing the elements of collections without exposing the internal details. 

Use case. Mostly, I use it to provide a standard way of traversing the collections. 

Clean client code (Single Responsibility Principle).

Introducing iterators in collections is possible without changing the client’s code (Open/Closed Principle).

Each iteration object has its own iteration state, so you can delay & continue iteration.

Use of iterators with simple collections can overload the application.  


Iterator design pattern in Python

Code example

from __future__ import annotations
from import Iterable, Iterator
from typing import Any, List

class AlphabeticalOrderIterator(Iterator):
    _position: int = None
    _reverse: bool = False

    def __init__(self, collection: WordsCollection, 
                 reverse: bool = False):
        self._collection = collection
        self._reverse = reverse
        self._position = -1 if reverse else 0

    def __next__(self):
            value = self._collection[self._position]
            self._position += -1 if self._reverse else 1
        except IndexError:
            raise StopIteration()
        return value

class WordsCollection(Iterable):
    def __init__(self, collection: List[Any] = []):
        self._collection = collection

    def __iter__(self) -> AlphabeticalOrderIterator:
        return AlphabeticalOrderIterator(self._collection)

    def get_reverse_iterator(self) -> AlphabeticalOrderIterator:
        return AlphabeticalOrderIterator(self._collection, True)

    def add_item(self, item: Any):

if __name__ == "__main__":
    collection = WordsCollection()

    print("Straight traversal:")

    print("Reverse traversal:")


State helps an object to alter its behavior in case its internal state changes. 

Use case. State helps me

  • Alter the enormous number of object states. 
  • Reduce the number of lines with duplicate code in similar transitions & states.
  • Avoid massive conditionals.

Follows Single Responsibility principle: separate classes for the code related to a different state.

Doesn’t change the context or state of classes when adding new states (Open/Closed Principle).

Using State can be too much in case the state machine isn’t almost changing.


State design pattern in Python

Code example  

from __future__ import annotations
from abc import ABC, abstractmethod

class Context(ABC):
    _state = None

    def __init__(self, state: State):

    def transition_to(self, state: State):
        print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self

    def request1(self):

    def request2(self):

class State(ABC):
    def context(self) -> Context:
        return self._context

    def context(self, context: Context):
        self._context = context

    def handle1(self):

    def handle2(self):

class ConcreteStateA(State):
    def handle1(self):
        print("ConcreteStateA handles request1.")
        print("ConcreteStateA wants to change the state of the context.")

    def handle2(self):
        print("ConcreteStateA handles request2.")

class ConcreteStateB(State):
    def handle1(self):
        print("ConcreteStateB handles request1.")

    def handle2(self):
        print("ConcreteStateB handles request2.")
        print("ConcreteStateB wants to change the state of the context.")

if __name__ == "__main__":
    context = Context(ConcreteStateA())


Observer notifies about events happening in other objects they observe without coupling to their classes. 

Use case. Each time I need to add the subscription mechanism to let an object subscribe to/ unsubscribe from notifications on the events happening with a specific publisher class, I use the Observer pattern. 

A good example is a simple subscription to news from any online magazine, frequently with the option to choose your sphere of interest (science, digital technology, etc.). Alternatively, the button “Notify me when it’s in stock” for e-commerce platforms is another example.

You haven’t to change the publisher’s code to add subscribers’ classes.

Subscribers get notifications in random order. 


Observer design pattern in Python

Code example

from __future__ import annotations
from abc import ABC, abstractmethod
from random import randrange
from typing import List

class Subject(ABC):
    def attach(self, observer: Observer):

    def detach(self, observer: Observer):

    def notify(self):

class ConcreteSubject(Subject):
    _state: int = None
    _observers: List[Observer] = []
    def attach(self, observer: Observer):
        print("Subject: Attached an observer.")

    def detach(self, observer: Observer):

    def notify(self):
        print("Subject: Notifying observers...")
        for observer in self._observers:

    def some_business_logic(self):
        print("Subject: I'm doing something important.")
        self._state = randrange(0, 10)
        print(f"Subject: My state has just changed to: {self._state}")

class Observer(ABC):
    def update(self, subject: Subject):       

class ConcreteObserverA(Observer):
    def update(self, subject: Subject):
        if subject._state < 3:
            print("ConcreteObserverA: Reacted to the event")

class ConcreteObserverB(Observer):
    def update(self, subject: Subject):
        if subject._state == 0 or subject._state >= 2:
            print("ConcreteObserverB: Reacted to the event")

if __name__ == "__main__":    
    subject = ConcreteSubject()

    observer_a = ConcreteObserverA()

    observer_b = ConcreteObserverB()




    Subscribe to our newsletter

    No spam, only hot&fresh posts from team

    Every month our subscribers get awesome updates

    Structural patterns


    Facade provides a simplified yet limited interface to decrease the complexity of an application. Complex subsystems with multiple moving parts could be “masked” by Facade. 

    Use case. I create the Facade class in case I have to work with complex libraries & APIs and/ or I need only the part of their functionality. 

    System complexity is separated from the code

    Using the Facade pattern, you can create a god object. 


    Facade design pattern in Python

    Code example

    class Addition:
        def __init__(self, field1: int, field2: int):
            self.field1 = field1
            self.field2 = field2
        def get_result(self):
            return self.field1 + self.field2
    class Multiplication:
        def __init__(self, field1: int, field2: int):
            self.field1 = field1
            self.field2 = field2
        def get_result(self):
            return self.field1 * self.field2
    class Subtraction:
        def __init__(self, field1: int, field2: int):
            self.field1 = field1
            self.field2 = field2
        def get_result(self):
            return self.field1 - self.field2
    class Facade:
        def make_addition(*args) -> Addition:
            return Addition(*args)
        def make_multiplication(*args) -> Multiplication:
            return Multiplication(*args)
        def make_subtraction(*args) -> Subtraction:
            return Subtraction(*args)
    if __name__ == "__main__":
        addition_obj = Facade.make_addition(5, 5)
        multiplication_obj = Facade.make_multiplication(5, 2)
        subtraction_obj = Facade.make_subtraction(15, 5)


    Decorator attaches new behaviors to the objects without modifying their structure. 

    The pattern produces a decorator class to wrap the original one and add new functionality.  

    Use case. I use the Decorator pattern each time I need to add extra behaviors to objects without getting into the code. 

    Changes the object behavior without creating a subclass.

    ➕ You can combine several behaviors by wrapping an object into multiple decorators.

    A specific decorator is hard to remove from the wrappers stack. 


    Decorator design pattern in Python

    Code example 

    class my_decorator:
        def __init__(self, func):
            print("inside my_decorator.__init__()")
            func() # Prove that function definition has completed
        def __call__(self):
            print("inside my_decorator.__call__()")
    def my_function():
        print("inside my_function()")
    if __name__ == "__main__":    


    Adapter serves as the middle-layer class to join functionalities of either independent or incompatible interfaces.

    Use case. Setting up the collaboration between the interfaces, I use the Adapter pattern to resolve the problem of incompatible formats. 

    For example, Adapter could help convert XML data format to JSON for further analysis. 

    Allows separating the interface from business logic.

    Adding new adapters doesn’t break the client’s code

    Increases the code complexity


    Adapter design pattern in Python

    Code example

    class Target:
        def request(self):
            return "Target: The default target's behavior."
    class Adaptee:
        def specific_request(self):
            return ".eetpadA eht fo roivaheb laicepS"
    class Adapter(Target, Adaptee):
        def request(self):
            return f"Adapter: (TRANSLATED) {self.specific_request()[::-1]}"
    def client_code(target: "Target"):
    if __name__ == "__main__":
        print("Client: I can work just fine with the Target objects:")
        target = Target()
        adaptee = Adaptee()
        print("Client: The Adaptee class has a weird interface. "
              "See, I don't understand it:")
        print(f"Adaptee: {adaptee.specific_request()}")
        print("Client: But I can work with it via the Adapter:")
        adapter = Adapter()

    Creational patterns


    Singleton restricts a class from having more than one instance and ensures a global access point to this instance. 

    Use case. Singleton helps me

    • Manage a shared resource: i.e. a single database, file manager, or printer spooler shared by multiple parts of the application. 
    • Store a global state (help filepath, user language, application path, etc.).
    • Create a simple logger.

    Class has a single instance

    Violates the SRP (Single Responsibility Principle). 

    ➖ It’s hard to unit test the code as the majority of test frameworks use inheritance when creating mock objects. 


    Singleton design pattern in Python

    Code example

    class Singleton:
        def __new__(cls):
            if not hasattr(cls, 'instance'):
                cls.instance = super(Singleton, cls).__new__(cls)
            return cls.instance
    if __name__ == "__main__":
        s = Singleton()
        print("Object created:", s)
        s1 = Singleton()
        print("Object created:", s1)

    When to use design patterns for Python?

    Facade is good when you need a unified interface for several API options. I.e. you should integrate a payment system in the application, leaving the possibility to change it. In this case, you could use the Facade pattern, and you’ll only have to create a new facade without rewriting the whole application.

    The problem here can emerge if only APIs are quite different, as it isn’t an easy task to design the common interface for facades.  

    State is used to manage the multiple independent components of an application provided that the initial architecture implies their independence. So, creating a separate module for state management can be a good idea, as well as using the Observer pattern. 

    Decorator is probably the most used Python pattern, because of in-built decorator support. For example, Decorator provides a convenient and explicit way to use some libraries and creates ever-richer opportunities for application design & management. The pattern also ensures a wide possibility for function composition and discovers new opportunities in functional programming. 

    Adapter is a fit when working with a big amount of data in different formats. The pattern allows using one algorithm instead of multiple ones for every data format. 

    The similar benefits Iterator has, so they are okay to be used together. In addition, one of the Iterator variations called Generator (introduced in Python long ago) allows using memory more efficiently working with big amounts of data that is highly valuable for some types of projects. 

    Finally, the importance of Singleton can’t be underestimated: database connection, working with API, working with files… These all are the moments when a developer should have a clear idea of how the process goes to avoid making mistakes. And Singleton can do a good job here, not to mention the possibility to reduce the memory consumption by using the same instance each time instead of duplicating it. 

    Got anything to add? Welcome to comments, господа!

    Leave a Reply

    Your email address will not be published. Required fields are marked *