Top Related Projects
An ultra-simplified explanation to design patterns
Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards.
Design patterns implemented in Java
A curated list of software and architecture related design patterns.
Everything you need to know to get the job.
📝 Algorithms and data structures implemented in JavaScript with explanations and links to further readings
Quick Overview
The python-patterns repository on GitHub is a collection of design patterns and idioms in Python. It provides a comprehensive overview of various design patterns and their implementation in the Python programming language. The repository serves as a valuable resource for developers looking to enhance their understanding and application of design patterns in their Python projects.
Pros
- Comprehensive Coverage: The repository covers a wide range of design patterns, including Creational, Structural, and Behavioral patterns, providing a thorough exploration of these concepts in the context of Python.
- Practical Examples: Each design pattern is accompanied by clear and concise code examples, making it easier for developers to understand the practical application of these patterns.
- Active Community: The project has an active community of contributors, ensuring regular updates and improvements to the content.
- Educational Resource: The repository can be an excellent learning resource for developers, especially those new to design patterns or Python, as it offers a structured and organized way to explore these concepts.
Cons
- Lack of Detailed Explanations: While the code examples are helpful, the repository could benefit from more detailed explanations and discussions of the design patterns, their use cases, and their trade-offs.
- Uneven Quality: The quality and depth of the examples may vary across different design patterns, as the repository is a community-driven project.
- Potential Outdated Content: As with any community-driven project, there is a risk of some content becoming outdated over time, especially with the rapid evolution of Python and its ecosystem.
- Limited Practical Guidance: The repository focuses more on the theoretical aspects of design patterns and their implementation, and may lack practical guidance on how to apply them in real-world scenarios.
Code Examples
Here are a few code examples from the python-patterns repository:
Singleton Pattern
The Singleton pattern ensures that a class has only one instance and provides a global point of access to it.
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
Factory Method Pattern
The Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate.
class Pizza:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class CheesePizza(Pizza):
def __init__(self):
super().__init__("Cheese Pizza")
class VeggiePizza(Pizza):
def __init__(self):
super().__init__("Veggie Pizza")
class PizzaFactory:
@staticmethod
def create_pizza(pizza_type):
if pizza_type == "cheese":
return CheesePizza()
elif pizza_type == "veggie":
return VeggiePizza()
else:
raise ValueError("Invalid pizza type")
Observer Pattern
The Observer pattern defines a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated automatically.
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self):
for observer in self._observers:
observer.update(self)
class ConcreteSubject(Subject):
def __init__(self, initial_state):
super().__init__()
self._state = initial_state
@property
def state(self):
return self._state
@state.setter
def state(self, value):
self._state = value
self.notify()
class Observer:
def update(self, subject):
print(f"Observed state change: {subject.state}")
Getting Started
To get started with the python-patterns repository, follow these steps:
-
Clone the repository to your local machine:
git clone https://github.com/faif/python-patterns.git -
Navigate to the project directory:
Competitor Comparisons
An ultra-simplified explanation to design patterns
Error generating comparison
Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards.
Pros of system-design-primer
- Comprehensive coverage of system design concepts and principles
- Includes interactive diagrams and visual aids for better understanding
- Provides real-world examples and case studies of large-scale systems
Cons of system-design-primer
- Focuses on high-level system design rather than specific programming patterns
- May be overwhelming for beginners due to its extensive content
- Less hands-on coding examples compared to python-patterns
Code comparison
While a direct code comparison isn't particularly relevant due to the different focus of these repositories, here's a brief example of how they differ in approach:
python-patterns (Strategy pattern):
class Strategy:
def __init__(self, func=None):
self.name = "Default Strategy"
if func:
self.execute = func
def execute(self):
print(f"{self.name} is used!")
system-design-primer (System design example):
Client -> DNS -> Load Balancer -> Web Server -> Application Server -> Database
The python-patterns repository focuses on implementing design patterns in Python, while system-design-primer provides high-level system architecture diagrams and explanations.
Design patterns implemented in Java
Pros of java-design-patterns
- More comprehensive, covering a wider range of design patterns
- Better organized with clear categorization and documentation
- Includes real-world examples and use cases for each pattern
Cons of java-design-patterns
- Larger codebase, potentially overwhelming for beginners
- Java-specific implementations may not translate easily to other languages
- More complex project structure due to its size and scope
Code Comparison
python-patterns (Strategy pattern):
class Strategy:
def __init__(self, function=None):
self.name = "Default Strategy"
if function:
self.execute = function
def execute(self):
print(f"{self.name} is used!")
java-design-patterns (Strategy pattern):
public interface Strategy {
int doOperation(int num1, int num2);
}
public class OperationAdd implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
Summary
Both repositories offer valuable resources for learning design patterns. python-patterns is more concise and Python-focused, making it easier for Python developers to grasp quickly. java-design-patterns provides a more extensive collection of patterns with detailed explanations and examples, but its Java-centric approach may require adaptation for use in other languages.
A curated list of software and architecture related design patterns.
Pros of awesome-design-patterns
- Covers a wide range of programming languages and design patterns
- Includes links to external resources and articles for deeper learning
- Provides a curated list of high-quality design pattern implementations
Cons of awesome-design-patterns
- Lacks detailed explanations or code examples within the repository
- May be overwhelming for beginners due to the large amount of information
Code comparison
python-patterns provides concrete Python implementations:
class Singleton:
__instance = None
def __new__(cls):
if cls.__instance is None:
cls.__instance = super().__new__(cls)
return cls.__instance
awesome-design-patterns doesn't include code examples directly, but links to external resources:
- [Singleton](https://en.wikipedia.org/wiki/Singleton_pattern)
- [Python Singleton](https://github.com/faif/python-patterns/blob/master/patterns/creational/singleton.py)
Summary
python-patterns focuses on Python-specific implementations with detailed explanations, while awesome-design-patterns offers a broader overview of design patterns across multiple languages. python-patterns is more suitable for Python developers looking for practical examples, whereas awesome-design-patterns serves as a comprehensive reference guide for various programming languages and paradigms.
Everything you need to know to get the job.
Pros of interviews
- Covers a broader range of topics including algorithms, data structures, and system design
- Includes solutions in multiple programming languages (Java, Python, C++)
- Provides a comprehensive resource for technical interview preparation
Cons of interviews
- Less focused on specific design patterns compared to python-patterns
- May not provide as in-depth explanations for each pattern or concept
- Could be overwhelming for beginners due to the large amount of content
Code Comparison
python-patterns (Strategy Pattern):
class Strategy:
def __init__(self, function=None):
self.name = "Default Strategy"
if function:
self.execute = function
def execute(self):
print(f"{self.name} is used!")
interviews (Binary Search Tree):
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
Both repositories provide valuable resources for developers, but they serve different purposes. python-patterns focuses on implementing design patterns in Python, while interviews covers a wider range of topics for technical interview preparation across multiple languages.
📝 Algorithms and data structures implemented in JavaScript with explanations and links to further readings
Pros of javascript-algorithms
- Extensive collection of algorithms and data structures
- Well-organized with detailed explanations and complexity analysis
- Includes unit tests for each implementation
Cons of javascript-algorithms
- Focused solely on algorithms, lacking design patterns
- May be overwhelming for beginners due to its comprehensive nature
Code Comparison
python-patterns (Strategy Pattern):
class Strategy:
def __init__(self, func=None):
self.name = "Default Strategy"
if func:
self.execute = func
def execute(self):
print(f"{self.name} is used!")
javascript-algorithms (Binary Search):
function binarySearch(sortedArray, seekElement) {
let startIndex = 0;
let endIndex = sortedArray.length - 1;
while (startIndex <= endIndex) {
const middleIndex = startIndex + Math.floor((endIndex - startIndex) / 2);
// ... (implementation continues)
}
}
Summary
While python-patterns focuses on design patterns in Python, javascript-algorithms provides a comprehensive collection of algorithms and data structures in JavaScript. The latter offers more depth in terms of algorithmic implementations but lacks coverage of design patterns. python-patterns is more suitable for learning software design principles, while javascript-algorithms is better for studying specific algorithms and their implementations.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
python-patterns
A collection of design patterns and idioms in Python.
Remember that each pattern has its own trade-offs. And you need to pay attention more to why you're choosing a certain pattern than to how to implement it.
Creational Patterns
Patterns that deal with object creation â abstracting and controlling how instances are made.
graph LR
Client -->|requests object| AbstractFactory
AbstractFactory -->|delegates to| ConcreteFactory
ConcreteFactory -->|produces| Product
Builder -->|step-by-step| Director
Director -->|returns| BuiltObject
FactoryMethod -->|subclass decides| ConcreteProduct
Pool -->|reuses| PooledInstance
| Pattern | Description |
|---|---|
| abstract_factory | use a generic function with specific factories |
| borg | a singleton with shared-state among instances |
| builder | instead of using multiple constructors, builder object receives parameters and returns constructed objects |
| factory | delegate a specialized function/method to create instances |
| lazy_evaluation | lazily-evaluated property pattern in Python |
| pool | preinstantiate and maintain a group of instances of the same type |
| prototype | use a factory and clones of a prototype for new instances (if instantiation is expensive) |
Structural Patterns
Patterns that define how classes and objects are composed to form larger, flexible structures.
graph TD
Client --> Facade
Facade --> SubsystemA
Facade --> SubsystemB
Facade --> SubsystemC
Client2 --> Adapter
Adapter --> LegacyService
Client3 --> Proxy
Proxy -->|controls access to| RealSubject
Component --> Composite
Composite --> Leaf1
Composite --> Leaf2
| Pattern | Description |
|---|---|
| 3-tier | data<->business logic<->presentation separation (strict relationships) |
| adapter | adapt one interface to another using a white-list |
| bridge | a client-provider middleman to soften interface changes |
| composite | lets clients treat individual objects and compositions uniformly |
| decorator | wrap functionality with other functionality in order to affect outputs |
| facade | use one class as an API to a number of others |
| flyweight | transparently reuse existing instances of objects with similar/identical state |
| front_controller | single handler requests coming to the application |
| mvc | model<->view<->controller (non-strict relationships) |
| proxy | an object funnels operations to something else |
Behavioral Patterns
Patterns concerned with communication and responsibility between objects.
graph LR
Sender -->|sends event| Observer1
Sender -->|sends event| Observer2
Request --> Handler1
Handler1 -->|passes if unhandled| Handler2
Handler2 -->|passes if unhandled| Handler3
Context -->|delegates to| Strategy
Strategy -->|executes| Algorithm
Originator -->|saves state to| Memento
Caretaker -->|holds| Memento
| Pattern | Description |
|---|---|
| chain_of_responsibility | apply a chain of successive handlers to try and process the data |
| catalog | general methods will call different specialized methods based on construction parameter |
| chaining_method | continue callback next object method |
| command | bundle a command and arguments to call later |
| interpreter | define a grammar for a language and use it to interpret statements |
| iterator | traverse a container and access the container's elements |
| iterator (alt. impl.) | traverse a container and access the container's elements |
| mediator | an object that knows how to connect other objects and act as a proxy |
| memento | generate an opaque token that can be used to go back to a previous state |
| observer | provide a callback for notification of events/changes to data |
| publish_subscribe | a source syndicates events/data to 0+ registered listeners |
| registry | keep track of all subclasses of a given class |
| servant | provide common functionality to a group of classes without using inheritance |
| specification | business rules can be recombined by chaining the business rules together using boolean logic |
| state | logic is organized into a discrete number of potential states and the next state that can be transitioned to |
| strategy | selectable operations over the same data |
| template | an object imposes a structure but takes pluggable components |
| visitor | invoke a callback for all items of a collection |
Design for Testability Patterns
| Pattern | Description |
|---|---|
| dependency_injection | 3 variants of dependency injection |
Fundamental Patterns
| Pattern | Description |
|---|---|
| delegation_pattern | an object handles a request by delegating to a second object (the delegate) |
Others
| Pattern | Description |
|---|---|
| blackboard | architectural model, assemble different sub-system knowledge to build a solution, AI approach - non gang of four pattern |
| graph_search | graphing algorithms - non gang of four pattern |
| hsm | hierarchical state machine - non gang of four pattern |
ð« Anti-Patterns
This section lists some common design patterns that are not recommended in Python and explains why.
ð§± Singleton
Why not:
- Python modules are already singletons â every module is imported only once.
- Explicit singleton classes add unnecessary complexity.
- Better alternatives: use module-level variables or dependency injection.
ð God Object
Why not:
- Centralizes too much logic in a single class.
- Makes code harder to test and maintain.
- Better alternative: split functionality into smaller, cohesive classes.
ð Inheritance overuse
Why not:
- Deep inheritance trees make code brittle.
- Prefer composition and delegation.
- âFavor composition over inheritance.â
Videos
- Design Patterns in Python by Peter Ullrich
- Sebastian BuczyÅski - Why you don't need design patterns in Python?
- You Don't Need That!
- Pluggable Libs Through Design Patterns
Contributing
When an implementation is added or modified, please review the following guidelines:
Docstrings
Add module level description in form of a docstring with links to corresponding references or other useful information. Add "Examples in Python ecosystem" section if you know some. It shows how patterns could be applied to real-world problems. facade.py has a good example of detailed description, but sometimes the shorter one as in template.py would suffice.
Python 2 compatibility
To see Python 2 compatible versions of some patterns please check-out the legacy tag.
Update README
When everything else is done - update corresponding part of README.
Travis CI
Please run the following before submitting a patch:
black .This lints your code.- Either
toxortox -e ci37for unit tests. - If you have a bash compatible shell, use
./lint.sh.
Contributing via issue triage 
You can triage issues and pull requests on CodeTriage.
Top Related Projects
An ultra-simplified explanation to design patterns
Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards.
Design patterns implemented in Java
A curated list of software and architecture related design patterns.
Everything you need to know to get the job.
📝 Algorithms and data structures implemented in JavaScript with explanations and links to further readings
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot