Jesse A. Green / notebook

python-patterns User Guide

Generated June 2026 from faif/python-patterns at 74151cf

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

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 dependencies list in pyproject.toml is 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-patterns and it packages the patterns/ 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 legacy git 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:

  1. 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.
  2. The pattern's classes and functions — the actual implementation.
  3. A main() function whose docstring is a doctest — the worked example, showing usage and expected output.
  4. 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.py reads command-line arguments, so running it without arguments raises an IndexError. Run it with a registered route and action instead:

python -m patterns.structural.mvc products show_items

Run the -m form from the repository root so Python can resolve the patterns package.

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 a FlyweightMeta metaclass that intercepts instance creation. It is verified by assert statements in its __main__ block rather than a doctest — run it with python patterns/structural/flyweight_with_metaclass.py and 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 like pyflakes) and the black formatter 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_provider stub (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

  1. Open the pattern file and read the top docstring for the why and the trade-offs.
  2. Read the main() docstring to see the pattern used end to end.
  3. 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 borg Monostate idiom if you need shared state). The closest creational idioms present are borg.py and factory.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.