1. Project Overview & Quickstart (faif/python-patterns)
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:
- If you have a bash-compatible shell, use
./lint.shto run formatting,
linting, type checking, and tests.
Development dependencies are pinned in Pipfile.lock. After changingPipfile, activate a Python 3.10 virtual environment and run make lock to
regenerate it.
Contributing via issue triage [](https://www.codetriage.com/faif/python-patterns)
You can triage issues and pull requests on CodeTriage.
2. Official Technical Reference & Guides (faif/docs)
The Things Network Documentation [](https://travis-ci.org/TheThingsNetwork/docs)
This is a Jekyll site which Travis automatically tests and builds to the gh-pages branch to be served via GitHub Pages.
Update content
If you do a lot of edits please use a local build to preview and test.
- The homepage for the site is index.html.
- The guides are a Jekyll collection in the _content folder.
- Store assets in the same folder as the markdown file you need it in and include them by their filename. You can also use relative paths to re-use images from other guides.
- To link to another child guide, use the relative markdown path (e.g.
../devices/registration.md) and Jekyll will make it.html. - To link to another parent guide, use the relative markdown path (e.g.
../devices/index.md) or the directory path, ending with a slash (../devices/). - Guides are sorted on descending
zindexfirst, thentitleascending and if those are equallabeldescending. - Use blockquotes (
>) to create callouts for important notes. - To set an image to use on Facebook and Twitter use
image:/absolute/path/to/image.pngin your frontmatter. - You can use most of the icons we use in the console. Simply use `` in the Markdown and we'll style it as a button.
Build local for preview and design
Install Bundler:
bash$ gem install bundlerInstall Jekyll using Bundler:
bash$ bundle installInstall Node.js and NPM.
Install front-end and development dependencies:
$ npm install> This will also overwrite any local git pre-commit hook to execute [npm run webpack](package.json#L12), [npm test](package.json#L15) and [npm run add](package.json#L16) to append the webpack build.Run Webpack, build the local Jekyll site and watch for changes:
bash$ npm run devBe aware that this will use Jekyll's experimental incremental mode. Only the file you edit will be regenerated. So a change in a guide's title will not cause the navigation on all other pages to be updated. Just kill the proces and run it again.
Guidance
- Require and use any JS libraries you need in assets/js/_main.js and _page.js.
- Import any Sass files you need in assets/css/main.scss.
- Override Bootstrap variables in _sass/_variables.scss.
- Edit styles in _sass/_base.scss or break out to additional Sass files to keep it organized.
- Store layout assets in assets folder.
- Edit layouts in the _layouts folder.
- All layouts should inherit the default layout.
Build and upload a preview
If you do some major refactoring and would like to upload a build somewhere for preview, then you can use:
npm run scp user@host:/pathThis will create a build in _scp, upload it with scp and then delete the directory. Make sure the server has your public key or it will prompt for a password and cause the script to fail.
Alternatively, you can set the SCP_TARGET environment variable or dotenv.
Test [](https://travis-ci.org/TheThingsNetwork/docs)
Pull Requests and Pushes will be tested automatically by Travis. It will let Jekyll try to build the site and then run HTMLProofer to test for broken links etc.
The test will also run automatically before every commit. To run the test manually, follow Build local to install the dependencies and then run:
npm testAutomatic updates
Some content we source directly from elsewhere, e.g. the MQTT API Reference.
Update
Follow the previous section to install NPM and dependencies.
Run the pull script:
bashnpm run pull
Source
To source more content from elsewhere edit _scripts/pull.js.