Python Design Patterns, Part One

In this article, I will cover several common Python design patterns.

Design Patterns

Design patterns are an attempt to bring a formal definition for correctly designed structures to software engineering. In software development, we may incorrectly choose or apply a design pattern, and create software that “collapses” under normal operating situations or when stressed beyond its original design limits.

Decorator Pattern

  • Enhancing the response of a component that is sending data to a second component
  • Supporting multiple optional behaviors


import time

def log_calls(func):
# Defines a new function
def wrapper(*args, **kwargs):
now = time.time()
print(f"Calling {func.__name__} with {args} and {kwargs}")
return_value = func(*args, **kwargs)
print(f"Executed {func.__name__} in {time.time() - now}ms")
return return_value
# Return the new function
return wrapper

def test1(a, b, c):
print(f"\t test1 called")

def test2(a, b):
print(f"\t test2 called")

def test3(a, b):
print(f"\t test1 called")

test1(1, 2, 3)
test2(4, b=5)
test3(6, 7)

Observer Pattern


class Inventory:
def __init__(self):
self.observers = []
self._product = None
self._quantity = 0

def attach(self, observer):

def product(self):
return self._product

def product(self, value):
self._product = value

def quantity(self):
return self._quantity

def quantity(self, value):
self._quantity = value

def _update_observers(self):
for observer in self.observers:

class ConsoleObserver:
def __init__(self, inventory):
self.inventory = inventory

def __call__(self):
if self.inventory.quantity > 4:
print(f"{self.inventory.product} has {self.inventory.quantity}, overload warning!")

The observer pattern detaches the code being monitored from the code doing the monitoring. Otherwise we would have had to put code in each of the properties to handle the different cases that might come up, logging to a file, update a database,..etc.

Strategy Pattern

State Pattern

To make state pattern work, we need a context manager that provides an interface for switching states. Internally, the manager contains a pointer to the current state; each state knows what other states it is allowed to be in and will transition to those states depending on actions invoked upon it. An XML parsing tool is a good example. The tool keeps eating eating characters from the XML file, looking for a specific value and change to its different state.

Singleton Pattern

class OneOnly:
_singleton = None

def __new__(cls, *args, **kwargs):
if not cls._singleton:
cls._singleton = super(OneOnly, cls).__new__(cls, *args, **kwargs)
return cls._singleton

Template Pattern

A typical example is database operations, when doing database operations, we need to perform the following common steps:

  • Connect to database
  • Construct a query
  • Issue the query
  • Parse the result
  • Output the data

We could create a database template class as follows:

class QueryTemplate:
def connect(self):
def construct_query(self):
def do_query(self):
def parse_results(self):
def output_results(self):
def process_query(self):
class NewUserQuery(QueryTemplate):
def construct_query(self):
self.query = "select * from Users where new='true'"

Senior Cloud and DevOps Engineer from both HighTech and FinTech world.