Understanding and Using Design Patterns in Python
PythonTimes.com Exclusive Article

Design patterns represent the best practices used by experienced object-oriented software developers. They’re solutions to general problems that software developers faced during software development, that are reusable in many different types of code. Design patterns can speed up the development process by providing tested, proven development paradigms. In this article, we will delve into design patterns and how we can use them in Python.
Table of Contents
- What is a Design Pattern?
- Types of Design Patterns
- Creational Design Patterns
- Structural Design Patterns
- Behavioral Design Patterns
- Conclusion
1. What is a Design Pattern?
A design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. Design patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system [^1^].
[^1^]: Design Patterns in Python
2. Types of Design Patterns
Design patterns can be classified into three categories: Creational, Structural, and Behavioral patterns.
-
Creational Patterns: These design patterns provide a way to create objects while hiding the creation logic, rather than instantiating objects directly using a
new
operator. This gives the program more flexibility in deciding which objects need to be created for a given use case. -
Structural Patterns: These design patterns concern class and object composition. They focus on how classes and objects can be combined to form larger structures.
-
Behavioral Patterns: These design patterns are specifically concerned with communication between objects.
3. Creational Design Patterns
In Python, creational design patterns aim to solve issues with object creation mechanisms, trying to provide suitable solutions for different situations.
Let’s take a look at two common creational patterns: Singleton and Factory.
Singleton
The singleton pattern is a design pattern that restricts the instantiation of a class to a “single” instance.
Here is a simple example of a singleton pattern in Python:
class Singleton:
__instance = None
def __init__(self):
if not Singleton.__instance:
print("__init__ method called.")
else:
print("Instance already created:", self.getInstance())
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance
Factory
The factory pattern is a creational pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.
Here’s how we might define a simple CarFactory
:
class CarFactory:
def createCar(self, type):
pass
class SportsCarFactory(CarFactory):
def createCar(self, type):
return SportsCar()
class FamilyCarFactory(CarFactory):
def createCar(self, type):
return FamilyCar()
4. Structural Design Patterns
Structural patterns in Python are all about class and object composition or, in other words, forming a bridge between two incompatible interfaces. Below, we discuss Adapter and Decorator patterns.
Adapter
The adapter pattern works as a bridge between two incompatible interfaces. This pattern involves a single class, the adapter, which is responsible for communication between two different interfaces.
Here’s a simple implementation of the Adapter
pattern:
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]}"
Decorator
The decorator pattern allows you to add new functionality to an existing object without altering its structure.
Here’s a simple implementation of the Decorator
pattern:
def decorator_function(original_function):
def wrapper_function():
print("Wrapper executed this before {}".format(original_function.__name__))
return original_function()
return wrapper_function
@decorator_function
def display():
print("display function ran")
display()
5. Behavioral Design Patterns
Behavioral design patterns are concerned with the interaction and responsibilities of objects. In Python, they are about packing a punch with the language features.
Let’s dive into two commonly used behavioral pattern: Observer and Strategy.
Observer
The observer pattern defines a subscription mechanism to notify multiple objects about any new events that happen to the object they’re observing.
Here’s an implementation of the Observer
pattern:
class Subject:
def __init__(self) -> None:
self._observers = []
def attach(self, observer) -> None:
self._observers.append(observer)
def detach(self, observer) -> None:
self._observers.remove(observer)
def notify(self) -> None:
for observer in self._observers:
observer.update(self)
Strategy
In strategy pattern, a class behavior or its algorithm can be changed at run time. This type of design pattern comes under behavior pattern.
Here’s an implementation of the Strategy
pattern:
class StrategyExample:
def __init__(self, func=None):
if func:
self.execute = func
def execute(self):
print("Original execution")
def executeReplacement1():
print("Strategy 1")
def executeReplacement2():
print("Strategy 2")
strategy1 = StrategyExample(executeReplacement1)
strategy1.execute() # Outputs: Strategy 1
6. Conclusion
Design patterns are a boon for developers, new and experienced alike. They provide reusable models for coding against unpredictable project requirements, ensuring that they can evolve and scale over time. Not only they make our code more efficient and speed up our development process, but they also give us a common language with which to architect, discuss and troubleshoot our systems.
Remember, the purpose of design patterns is to provide you with a way to solve issues related to software design using a proven solution. This allows for significant reductions in time and improvements in efficiency by reusing these patterns and paradigms.
In Python, we have access to some incredibly powerful design patterns that can streamline our development work, as demonstrated throughout this article. Whichever design pattern you choose to use, remember that the goal is to make your code more flexible, efficient, and maintainable.
While we have explored a few design patterns in this article, there’s a whole host of other patterns to discover, so keep learning, keep coding, and let’s build fantastic Python programs!
Author: An Expert Python Developer at PythonTimes.com