python-patterns is a curated collection of design patterns and idioms implemented in modern Python. It is not an application you install and run, and not a library you import into your project. It is a reference catalog: each pattern lives in its own small, self-contained .py file that both explains the pattern (in a module docstring) and demonstrates it (in runnable, testable examples). You read a file, run it to watch the example execute, then adapt the idiom into your own code.
This guide shows you how to get the collection on your machine, how to run any pattern and see its output, how to read a pattern file, and provides a complete catalog of every pattern in the repository — organized exactly the way the project organizes them.
Note
The guiding philosophy of this project, stated in its README, is: "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." Use this catalog to learn the vocabulary of patterns and their trade-offs — not as code to copy verbatim into production.
1. Quick Start
You do not need to install anything to read or run a single pattern. If you have Python 3.10 or newer, you can clone the repository and run any pattern file directly.
git clone https://github.com/faif/python-patterns.git
cd python-patterns
python patterns/creational/factory.py
The command above prints nothing — and that is success. Every pattern file ends with an embedded doctest suite that runs when you execute the file. Silence means every example in the file produced exactly the output it documented.
To actually see the pattern run its examples step by step, run the file through doctest in verbose mode:
python -m doctest -v patterns/creational/factory.py
Trying:
e, g = get_localizer(language="English"), get_localizer(language="Greek")
Expecting nothing
ok
Trying:
for msg in "dog parrot cat bear".split():
print(e.localize(msg), g.localize(msg))
Expecting:
dog σκύλος
parrot parrot
cat γάτα
bear bear
ok
...
2 items passed all tests
Tip
The fastest way to understand a pattern is to open its file and read the
main()docstring. That docstring is a transcript of the pattern being used — inputs on>>>lines, expected outputs directly beneath. It is simultaneously the documentation, the example, and the test.
2. Requirements
| Requirement | Detail |
|---|---|
| Python | 3.10 or newer (requires-python = ">=3.10"; classifiers cover 3.10, 3.11, 3.12, 3.13) |
| Runtime dependencies | None. Every pattern uses only the Python standard library. |
| Git | Recommended, to clone the repository |
| Operating system | Any platform with a supported Python (Linux, macOS, Windows) |
Important
There are no third-party runtime dependencies. The
dependencieslist inpyproject.tomlis empty. Everything you run here works on a clean Python install. The packages listed under[project.optional-dependencies].dev(black, flake8, mypy, pytest, tox, and friends) are only needed if you intend to contribute or run the full test/lint suite — see the Admin Guide for those.
3. Installation
For simply reading and running patterns, cloning is all you need — no install step:
Clone (recommended)
git clone https://github.com/faif/python-patterns.git
cd python-patterns
python patterns/behavioral/observer.py
Download a single file
Each pattern is fully self-contained and uses only the standard library. You can copy a single file out of the repository (for example, from the GitHub web UI) and run it on its own:
python observer.py
Editable install (for running tests)
If you want to run the project's pytest suite, install the package in editable mode with its dev extras. This registers the patterns package so the tests can import it:
python -m pip install -e ".[dev]"
Note
The editable install exists to support testing and linting, not to expose an importable API. The package name is
python-patternsand it packages thepatterns/directory, but the modules are designed to be read and run, not imported as a dependency in your own application.
Tip
Want the older Python 2-compatible versions of some patterns? They are preserved on the repository's
legacygit tag:git checkout legacy.
4. How to Run and Read a Pattern
Every pattern file follows the same convention, so once you learn one, you can navigate all of them.
4.1 The anatomy of a pattern file
A typical file has four parts:
- A module docstring at the top explaining what the pattern is about, what the example does, where it is used in the real world, and a one-line
*TL;DR. - The pattern's classes and functions — the actual implementation.
- A
main()function whose docstring is a doctest — the worked example, showing usage and expected output. - A
__main__guard that runs the doctests when you execute the file.
def main():
"""
>>> e, g = get_localizer(language="English"), get_localizer(language="Greek")
>>> for msg in "dog parrot cat bear".split():
... print(e.localize(msg), g.localize(msg))
dog σκύλος
parrot parrot
cat γάτα
bear bear
"""
if __name__ == "__main__":
import doctest
doctest.testmod()
4.2 Three ways to run
| Goal | Command | What you see |
|---|---|---|
| Verify a pattern's examples pass | python patterns/<category>/<name>.py |
Nothing on success; a diff on failure |
| Watch every example execute | python -m doctest -v patterns/<category>/<name>.py |
Each >>> line, its expected output, and ok |
| Run all in-file examples at once | pytest --doctest-modules patterns/ |
A pytest summary across every pattern |
Warning
A handful of files do more than run doctests in their
__main__block. For example,patterns/structural/mvc.pyreads command-line arguments, so running it without arguments raises anIndexError. Run it with a registered route and action instead:python -m patterns.structural.mvc products show_itemsRun the
-mform from the repository root so Python can resolve thepatternspackage.
4.3 The categories
Patterns are grouped the same way the classic Gang of Four taxonomy groups them, plus a few project-specific buckets:
patterns/
├── creational/ How objects get made
├── structural/ How objects and classes compose into larger structures
├── behavioral/ How objects communicate and divide responsibility
├── fundamental/ Foundational idioms (delegation)
├── dependency_injection.py Design-for-testability
└── other/ Useful patterns outside the GoF set
5. Pattern Catalog
This is the heart of the collection. Each entry gives you the one-line summary, the file to open, the command to run it, and the key idea to take away. Patterns are listed in the project's own order.
5.1 Creational Patterns
Patterns that deal with object creation — abstracting and controlling how instances are made.
Abstract Factory — patterns/creational/abstract_factory.py
Provides a way to encapsulate a group of individual factories. In the example, a PetShop is handed an animal factory (the Dog or Cat class itself, since classes are callable in Python) and uses it to produce pets without knowing the concrete type up front.
python -m doctest -v patterns/creational/abstract_factory.py
>>> cat_shop = PetShop(Cat)
>>> pet = cat_shop.buy_pet("Lucy")
Here is your lovely Cat<Lucy>
>>> pet.speak()
meow
Tip
In Python you rarely need a separate factory class — a class or a plain function already serves as the "callable that creates an object." This example leans on that fact deliberately.
Borg (Monostate) — patterns/creational/borg.py
Provides singleton-like behavior by sharing state across instances instead of sharing identity. Every Borg instance points its __dict__ at one shared class-level dictionary, so attributes set on any instance are visible from all of them — yet the instances remain distinct objects.
>>> rm1, rm2 = YourBorg(), YourBorg()
>>> rm1.state = 'Idle'
>>> rm2.state = 'Running'
>>> print(rm1) # rm1 reflects rm2's change
Running
>>> rm1 is rm2
False
Note
This is the project's answer to the Singleton question. A true Singleton is listed as an anti-pattern (see §7) — the Borg/Monostate idiom shares state without forcing a single instance.
Builder — patterns/creational/builder.py
Decouples the construction of a complex object from its representation, so the same process can build different products. The example shows two styles: a Building base class whose __init__ calls the build steps, and a ComplexBuilding whose steps are driven by an external construct_building() function.
>>> house = House()
>>> house
Floor: One | Size: Big
>>> complex_house = construct_building(ComplexHouse)
>>> complex_house
Floor: One | Size: Big and fancy
Factory — patterns/creational/factory.py
Creates objects without the caller specifying the exact class. get_localizer(language=...) returns an EnglishLocalizer or GreekLocalizer; the caller just calls .localize(...) the same way regardless.
>>> e, g = get_localizer(language="English"), get_localizer(language="Greek")
>>> g.localize("dog")
'σκύλος'
>>> e.localize("dog")
'dog'
Lazy Evaluation — patterns/creational/lazy_evaluation.py
Delays computing a property's value until it is first accessed, then caches it. Two implementations are shown: a lazy_property descriptor and a lazy_property2 decorator. After first access the computed value lands directly in the instance __dict__, so later reads skip the work.
>>> Jhon = Person('Jhon', 'Coder')
>>> Jhon.relatives # computed on first access
'Many relatives.'
>>> Jhon.parents # cached after the first call
'Father and mother'
>>> Jhon.call_count2 # the expensive body ran only once
1
Pool — patterns/creational/pool.py
Keeps a set of initialized objects ready to reuse, so you skip the cost of recreating expensive objects. The ObjectPool checks an object out of a queue.Queue and returns it on context-manager exit (or on garbage collection).
>>> sample_queue.put('yam')
>>> with ObjectPool(sample_queue) as obj:
... print('Inside with: {}'.format(obj))
Inside with: yam
>>> print('Outside with: {}'.format(sample_queue.get())) # returned to the pool
Outside with: yam
Prototype — patterns/creational/prototype.py
Creates new objects by cloning a prototypical instance instead of subclassing. A PrototypeDispatcher registers named prototypes; clients clone from them, overriding only the attributes they need.
>>> prototype = Prototype()
>>> a = prototype.clone(value='a-value', category='a')
>>> b = a.clone(value='b-value', is_checked=True)
>>> print(b.category, b.is_checked)
a True
| Pattern | File | TL;DR |
|---|---|---|
| Abstract Factory | creational/abstract_factory.py |
Encapsulate a group of factories |
| Borg | creational/borg.py |
Singleton-like shared state across instances |
| Builder | creational/builder.py |
Separate complex construction from representation |
| Factory | creational/factory.py |
Create objects without naming the exact class |
| Lazy Evaluation | creational/lazy_evaluation.py |
Compute a property once, on first use |
| Pool | creational/pool.py |
Reuse a set of pre-initialized objects |
| Prototype | creational/prototype.py |
Clone a prototypical instance |
5.2 Structural Patterns
Patterns that define how classes and objects are composed to form larger, flexible structures.
3-Tier — patterns/structural/3-tier.py
Separates presentation, business logic, and data management into strict layers. The Ui talks only to BusinessLogic, which talks only to the Data store.
>>> ui = Ui()
>>> ui.get_product_information("cheese")
(Fetching from Data Store)
PRODUCT INFORMATION:
Name: Cheese, Price: 2.00, Quantity: 10
Adapter — patterns/structural/adapter.py
Lets an existing class be used through a different interface. Adapter wraps an object and exposes its bark/meow/speak methods under a uniform make_noise() name, by injecting them into the wrapper's __dict__.
>>> objects = [Adapter(Dog(), make_noise=Dog().bark)]
>>> for obj in objects:
... print("A {0} goes {1}".format(obj.name, obj.make_noise()))
A Dog goes woof!
Bridge — patterns/structural/bridge.py
Decouples an abstraction from its implementation so the two can vary independently. CircleShape (abstraction) delegates drawing to an interchangeable DrawingAPI1/DrawingAPI2 (implementation).
>>> shape = CircleShape(1, 2, 3, DrawingAPI1())
>>> shape.scale(2.5)
>>> shape.draw()
API1.circle at 1:2 radius 7.5
Composite — patterns/structural/composite.py
Lets clients treat individual objects and compositions of objects uniformly. A CompositeGraphic holds a list of Graphic children (which may themselves be composites) and renders them as a tree.
>>> graphic = CompositeGraphic()
>>> graphic.add(graphic1) # graphic1 is itself a composite of ellipses
>>> graphic.render()
Ellipse: 1
Ellipse: 2
...
Decorator — patterns/structural/decorator.py
Adds behavior to an object without altering its class. BoldWrapper and ItalicWrapper each wrap a TextTag and can be stacked, so the inner text picks up <b> then <i> tags.
>>> special_hello = ItalicWrapper(BoldWrapper(TextTag("hello, world!")))
>>> special_hello.render()
'<i><b>hello, world!</b></i>'
Facade — patterns/structural/facade.py
Provides one simple interface to a more complex subsystem. ComputerFacade.start() hides the orchestration of CPU, Memory, and SolidStateDrive behind a single call.
>>> ComputerFacade().start()
Freezing processor.
Loading from 0x00 data: 'Some data from sector 100 with size 1024'.
Jumping to: 0x00
Executing.
Flyweight — patterns/structural/flyweight.py
Minimizes memory by sharing identical objects instead of duplicating them. Card.__new__ returns an existing instance from a WeakValueDictionary pool when one with the same value+suit already exists, so two "9h" cards are literally the same object.
>>> c1, c2 = Card('9', 'h'), Card('9', 'h')
>>> c1 is c2
True
Note
A second implementation,
patterns/structural/flyweight_with_metaclass.py, achieves the same pooling through aFlyweightMetametaclass that intercepts instance creation. It is verified byassertstatements in its__main__block rather than a doctest — run it withpython patterns/structural/flyweight_with_metaclass.pyand it passes silently.
Front Controller — patterns/structural/front_controller.py
Provides a single, centralized entry point that routes incoming requests. RequestController validates the request, then a Dispatcher sends it to the matching MobileView or TabletView.
>>> front_controller = RequestController()
>>> front_controller.dispatch_request(Request('mobile'))
Displaying mobile index page
MVC — patterns/structural/mvc.py
Separates data (Model), presentation (View), and coordination (Controller). This file also includes a small Router and an executable __main__ block that dispatches based on command-line arguments.
>>> controller = Controller(ProductModel(), ConsoleView())
>>> controller.show_item_information("cheese")
PRODUCT INFORMATION:
Name: cheese, Price: 2.00, Quantity: 10
Tip
To run MVC as a tiny CLI app, pass a route and an action:
python -m patterns.structural.mvc products show_items
Proxy — patterns/structural/proxy.py
Adds functionality (logging, access control, caching) in front of a real object without changing its interface. Proxy.do_the_job logs the request and only forwards to RealSubject for the admin user.
>>> proxy = Proxy()
>>> client(proxy, 'anonymous')
[log] Doing the job for anonymous is requested.
[log] I can do the job just for `admins`.
| Pattern | File | TL;DR |
|---|---|---|
| 3-Tier | structural/3-tier.py |
Strict data ↔ logic ↔ presentation separation |
| Adapter | structural/adapter.py |
Expose one interface as another |
| Bridge | structural/bridge.py |
Decouple abstraction from implementation |
| Composite | structural/composite.py |
Treat objects and groups uniformly |
| Decorator | structural/decorator.py |
Add behavior by wrapping |
| Facade | structural/facade.py |
One interface over a complex subsystem |
| Flyweight | structural/flyweight.py |
Share identical objects to save memory |
| Flyweight (metaclass) | structural/flyweight_with_metaclass.py |
Same pooling via a metaclass |
| Front Controller | structural/front_controller.py |
Centralized request entry point |
| MVC | structural/mvc.py |
Model ↔ View ↔ Controller |
| Proxy | structural/proxy.py |
Funnel operations through a stand-in |
5.3 Behavioral Patterns
Patterns concerned with communication and responsibility between objects.
Catalog — patterns/behavioral/catalog.py
Dispatches to one of several specialized methods based on a parameter passed at construction, using a dictionary instead of if/elif chains. Four variants are shown: static-method, instance-method, class-method, and pure-static catalogs.
>>> Catalog('param_value_2').main_method()
'executed method 2!'
Chain of Responsibility — patterns/behavioral/chain_of_responsibility.py
Passes a request along a chain of handlers until one handles it — an object-oriented if/elif/else whose branches can be rearranged at runtime. Each ConcreteHandler checks a numeric range and either handles the request or forwards it to its successor.
>>> h0.handle(14)
request 14 handled in handler 1
>>> h0.handle(35)
end of chain, no handler for 35
Chaining Method — patterns/behavioral/chaining_method.py
Returns objects from method calls so calls can be chained fluently. person.do_action(move).amount('5m').stop() reads as a single sentence.
>>> person.do_action(move).amount('5m').stop()
Jack move 5m then stop
Command — patterns/behavioral/command.py
Bundles an action and its receiver into an object you can invoke later — an object-oriented callback, often with an undo(). MenuItem holds a HideFileCommand or DeleteFileCommand and triggers it on press.
>>> item1 = MenuItem(DeleteFileCommand())
>>> item1.on_do_press('test-file')
deleting test-file
>>> item1.on_undo_press()
restoring test-file
Iterator — patterns/behavioral/iterator.py and iterator_alt.py
Traverses a container's elements without exposing its internals. Two implementations are provided: iterator.py uses a generator (yield from), and iterator_alt.py implements the full iterator protocol (__iter__/__next__) on a NumberWords class.
>>> for number in count_to_two(): # generator version
... print(number)
one
two
Mediator — patterns/behavioral/mediator.py
Encapsulates how a set of objects interact, so they communicate through a mediator rather than directly. User instances send messages through a shared ChatRoom.
>>> molly = User('Molly')
>>> molly.say("Hi Team! Meeting at 3 PM today.")
'[Molly says]: Hi Team! Meeting at 3 PM today.'
Memento — patterns/behavioral/memento.py
Captures an object's state so it can be restored later. The example builds a Transaction guard and a @Transactional decorator that roll an object back to its entry state if an operation raises.
>>> num_obj = NumObj(-1)
>>> a_transaction = Transaction(True, num_obj)
>>> # ... mutate, then a failure triggers rollback ...
>>> print(num_obj)
<NumObj: 2>
Observer — patterns/behavioral/observer.py
Maintains a list of dependents and notifies them of state changes. A Data subject notifies attached DecimalViewer / HexViewer observers whenever its value is set.
>>> data1.attach(DecimalViewer())
>>> data1.data = 10
DecimalViewer: Subject Data 1 has data 10
Tip
The module docstring points to real-world equivalents: Django Signals and Flask Signals are both Observer-pattern implementations you have probably already used.
Publish/Subscribe — patterns/behavioral/publish_subscribe.py
A Provider syndicates messages to zero or more subscribers registered per topic. Publishers push messages; the provider fans them out on update().
>>> jim.subscribe("cartoon")
>>> fftv.publish("cartoon")
>>> message_center.update()
jim got cartoon
Registry — patterns/behavioral/registry.py
Keeps track of every subclass of a base class automatically, using a RegistryHolder metaclass that records each new class as it is defined.
>>> class ClassRegistree(BaseRegisteredClass): ...
>>> sorted(RegistryHolder.REGISTRY)
['BaseRegisteredClass', 'ClassRegistree']
Servant — patterns/behavioral/servant.py
Offers shared functionality to a group of unrelated classes without inheritance. GeometryTools computes areas, perimeters, and moves for Circle and Rectangle, neither of which derives from it.
>>> GeometryTools().calculate_area(Circle(5, Position(0, 0)))
78.53981633974483
Specification — patterns/behavioral/specification.py
Lets you recombine business rules by chaining them with boolean logic (and, or, not). Specifications like UserSpecification and SuperUserSpecification compose into a single rule object.
>>> root = UserSpecification().and_specification(SuperUserSpecification())
>>> root.is_satisfied_by(ivan)
True
State — patterns/behavioral/state.py
Organizes behavior into discrete states and transitions between them. A Radio delegates scan() and toggle_amfm() to its current AmState or FmState.
>>> radio = Radio()
>>> radio.scan()
Scanning... Station is 1380 AM
Strategy — patterns/behavioral/strategy.py
Selects an algorithm at runtime by passing it in. An Order accepts a discount strategy function; a descriptor validates that the discount never drives the price negative.
>>> order = Order(100, discount_strategy=ten_percent_discount)
>>> order.apply_discount()
90.0
Template — patterns/behavioral/template.py
Defines the skeleton of an algorithm and lets pluggable components fill in the steps. template_function always gets then processes data, but the getter, converter, and saver are supplied by the caller.
>>> template_function(get_text, to_save=True)
Got `plain-text`
Skip conversion
[SAVE]
`plain-text` was processed
Visitor — patterns/behavioral/visitor.py
Separates an algorithm from the object structure it runs over. A Visitor dispatches to a visit_<ClassName> method by walking the node's MRO, falling back to generic_visit.
>>> visitor = Visitor()
>>> visitor.visit(C()) # C subclasses B, so visit_B is chosen
'visit_B C'
Tip
The Visitor docstring notes that Python's own
ast.NodeVisitor(used by tools likepyflakes) and theblackformatter both implement this pattern — a great place to see it at production scale.
| Pattern | File | TL;DR |
|---|---|---|
| Catalog | behavioral/catalog.py |
Dict-dispatch to specialized methods |
| Chain of Responsibility | behavioral/chain_of_responsibility.py |
Pass a request down a chain of handlers |
| Chaining Method | behavioral/chaining_method.py |
Fluent, chainable method calls |
| Command | behavioral/command.py |
Bundle an action for later, with undo |
| Iterator | behavioral/iterator.py |
Traverse a container (generator) |
| Iterator (alt.) | behavioral/iterator_alt.py |
Traverse a container (iterator protocol) |
| Mediator | behavioral/mediator.py |
Objects interact via a mediator |
| Memento | behavioral/memento.py |
Capture and restore state |
| Observer | behavioral/observer.py |
Notify dependents of changes |
| Publish/Subscribe | behavioral/publish_subscribe.py |
Fan out events to topic subscribers |
| Registry | behavioral/registry.py |
Auto-track subclasses |
| Servant | behavioral/servant.py |
Shared services without inheritance |
| Specification | behavioral/specification.py |
Recombine rules with boolean logic |
| State | behavioral/state.py |
Behavior driven by discrete states |
| Strategy | behavioral/strategy.py |
Swap algorithms at runtime |
| Template | behavioral/template.py |
Fixed skeleton, pluggable steps |
| Visitor | behavioral/visitor.py |
Separate an operation from a structure |
5.4 Fundamental Patterns
Foundational idioms that other patterns build on.
Delegation — patterns/fundamental/delegation_pattern.py
An object handles a request by delegating it to a second object. Delegator.__getattr__ forwards unknown attribute access to its wrapped Delegate, achieving the same reuse as inheritance through composition.
>>> delegator = Delegator(Delegate())
>>> delegator.p1
123
>>> delegator.do_something("nothing")
'Doing nothing'
5.5 Design-for-Testability Patterns
Dependency Injection — patterns/dependency_injection.py
Supplies an object's dependencies from outside rather than hard-coding them, which makes the dependency easy to substitute or mock in tests. Three variants are demonstrated: constructor injection, parameter injection, and setter injection.
>>> time_with_ci = ConstructorInjection(production_code_time_provider)
>>> time_with_ci.get_current_time_as_html_fragment()
'<span class="tinyBoldText">...</span>'
Tip
The
midnight_time_providerstub (return "24:01") in this file shows exactly why you inject: it lets the test pin "the current time" to a fixed value instead of depending on the real clock.
5.6 Other Patterns (non–Gang of Four)
Useful patterns outside the classic GoF set.
Blackboard — patterns/other/blackboard.py
An architectural pattern where several specialized "knowledge sources" (experts) collaborate on a shared Blackboard to assemble a solution incrementally. A Controller loops, letting each eager expert contribute until progress reaches 100%.
>>> blackboard.add_expert(Student(blackboard))
>>> c = Controller(blackboard)
>>> contributions = c.run_loop()
Note
This example seeds the random generator (
random.seed(1234)) in its__main__block so its doctest output is deterministic.
Graph Search — patterns/other/graph_search.py
Classic graph traversal algorithms packaged as a GraphSearch class: depth-first path finding (find_path_dfs, find_all_paths_dfs, find_shortest_path_dfs) and breadth-first shortest path (find_shortest_path_bfs).
>>> graph_search = GraphSearch(graph)
>>> graph_search.find_shortest_path_bfs('A', 'D')
['A', 'B', 'D']
Hierarchical State Machine (HSM) — patterns/other/hsm/hsm.py
A nested/hierarchical finite state machine. A HierachicalStateMachine holds Active, Standby, Suspect, and Failed states and transitions between them in response to message types such as "fault trigger" and "switchover". It defines its own exceptions: UnsupportedMessageType, UnsupportedState, and UnsupportedTransition.
| Pattern | File | TL;DR |
|---|---|---|
| Delegation | fundamental/delegation_pattern.py |
Reuse via composition, not inheritance |
| Dependency Injection | dependency_injection.py |
Supply dependencies from outside (3 variants) |
| Blackboard | other/blackboard.py |
Experts collaborate on shared state |
| Graph Search | other/graph_search.py |
DFS/BFS path-finding algorithms |
| HSM | other/hsm/hsm.py |
Hierarchical (nested) finite state machine |
6. Common Tasks
Run a single pattern and confirm it works
python patterns/behavioral/strategy.py
No output means all of the file's embedded examples passed.
See a pattern's examples execute, line by line
python -m doctest -v patterns/behavioral/strategy.py
Run every pattern's in-file examples at once
pytest --doctest-modules patterns/
This discovers and runs the doctest in every patterns/**/*.py file.
Run a pattern that has an executable entry point
mvc.py accepts arguments. Provide a route and an action:
python -m patterns.structural.mvc products show_items
PRODUCT LIST:
milk
eggs
cheese
Adapt a pattern into your own code
- Open the pattern file and read the top docstring for the why and the trade-offs.
- Read the
main()docstring to see the pattern used end to end. - Copy the classes/functions you need into your project. Every pattern is standard-library-only, so nothing else has to come with it.
Important
These files are teaching examples, intentionally minimal. Before using one in production, adapt it to your needs (error handling, type completeness, edge cases) — and reread the trade-offs in the docstring to confirm the pattern is actually the right tool for your problem.
7. Anti-Patterns: What This Project Deliberately Does Not Implement
The README includes an explicit Anti-Patterns section listing common patterns that the project recommends against in Python, and which therefore have no implementation file:
| Anti-pattern | Why it is discouraged here | Suggested alternative |
|---|---|---|
| Singleton | Python modules are already singletons (imported once); an explicit Singleton class adds needless complexity | Module-level variables, or dependency injection |
| God Object | Centralizes too much logic in one class; hard to test and maintain | Split into smaller, cohesive classes |
| Inheritance overuse | Deep inheritance trees make code brittle | "Favor composition over inheritance" — use composition and delegation |
Caution
If you came here looking for a Singleton or Interpreter implementation, note that neither exists in this repository. Singleton is intentionally excluded as an anti-pattern (use the
borgMonostate idiom if you need shared state). The closest creational idioms present areborg.pyandfactory.py. Do not assume a file exists for a pattern just because you have seen it elsewhere — consult the catalog in §5, which lists every file that actually ships.
8. Troubleshooting
Error: IndexError: list index out of range when running mvc.py
Cause: patterns/structural/mvc.py reads sys.argv[1] in its __main__ block. Running it with no arguments leaves nothing to read.
Solution: Pass a registered route and action.
python -m patterns.structural.mvc products show_items
Prevention: Most pattern files only run doctests in __main__; mvc.py is the exception that expects CLI arguments. Read the bottom of a file before running it directly.
Error: ValueError: Invalid Value for Param: <x>
Cause: The catalog.py classes validate their constructor argument against a fixed set of keys (param_value_1, param_value_2). Any other value raises this.
Solution: Pass one of the documented parameter values:
Catalog('param_value_1').main_method()
Prevention: Check the _static_method_choices (or _instance_method_choices / _class_method_choices) dictionary in the class to see the valid keys.
Error: ValueError: Unsupported shape type
Cause: servant.py's GeometryTools only knows how to handle Circle and Rectangle. Passing any other object raises this.
Solution: Use a supported shape, or extend GeometryTools with a branch for your new shape type.
Error: ValueError: Discount cannot be applied due to negative price resulting.
Cause: In strategy.py, a discount strategy that would push an Order's price below zero is rejected by the DiscountStrategyValidator descriptor; the order's strategy is set to None instead.
Solution: This is expected behavior, not a bug — choose a discount that leaves a non-negative price, or check order.discount_strategy before applying.
A doctest fails after I edited a pattern file
Cause: The main() docstring is a doctest. If you change a pattern's behavior or output, the expected text in the docstring no longer matches.
Solution: Update the expected output in the main() docstring to match the new behavior, then rerun:
python -m doctest -v patterns/<category>/<name>.py
Prevention: Treat the docstring examples as tests — keep them in sync with the code.
Running python -m patterns.structural.mvc ... fails with No module named patterns
Cause: The -m form requires Python to find the patterns package, which means running from the repository root.
Solution: cd into the cloned repository root before running the -m command.
python: command not found or an old Python runs
Cause: Your system Python may be older than 3.10, or python may map to Python 2.
Solution: Use an explicit interpreter (python3.12 patterns/...) and confirm python --version reports 3.10 or newer.
9. Frequently Asked Questions
Q: Is this a library I can pip install and import?
It is packaged so it can be installed in editable mode for testing, but it is not designed to be imported as a dependency. The intent is that you read each pattern and adapt its idiom into your own code. There are no stable public APIs to depend on.
Q: Do I need to install anything to run a pattern? No. Every pattern uses only the Python standard library. Clone the repo (or copy a single file) and run it with Python 3.10+.
Q: Why does running a pattern print nothing?
Because it passed. Each file runs its embedded doctests on execution and stays silent on success. Use python -m doctest -v <file> to see the examples run.
Q: How do I see a pattern actually do something?
Run it in verbose doctest mode (-m doctest -v) to watch each example execute, or read the main() docstring, which is a transcript of the pattern in use.
Q: Where is the Singleton pattern?
There isn't one — Singleton is intentionally listed as an anti-pattern. Use module-level state or dependency injection. If you specifically want shared state across instances, see borg.py (the Monostate idiom).
Q: Where is the Interpreter pattern?
There is no interpreter.py in this version of the repository. Use the catalog in §5 as the authoritative list of what actually ships.
Q: Why are there two iterator files and two flyweight files?
To show alternative implementations. iterator.py uses a generator while iterator_alt.py uses the explicit iterator protocol; flyweight.py pools via __new__ while flyweight_with_metaclass.py pools via a metaclass. Comparing them is part of the lesson.
Q: What Python versions are supported?
Python 3.10 and newer. Python 2-compatible versions of some patterns live on the repository's legacy git tag.
Q: How do I run all the examples to make sure everything works?
From the repository root: pytest --doctest-modules patterns/.
Q: Can I contribute a new pattern? Yes. The repository has a documented contribution process (docstring conventions, linting, tests). See the Admin Guide for the full workflow.
Q: Are these implementations production-ready? They are teaching examples — minimal by design. Adapt them (error handling, typing, edge cases) before production use, and confirm the pattern's trade-offs fit your problem.