Patterns

Patterns#

Cross-cutting style guidance that does not belong to any one type, function, or class. The Zen of Python distils the language’s design ethos into a checklist; the anti-patterns table catalogues what looks right but bites later. Both apply across every section of this handbook.

For the patterns that did live here, follow the move:

Topic

Now at

Looping idioms

Control flow

Comprehensions

Functions

Unpacking

Variables

Default values (dict)

dict

Mutable-default trap

Functions

Files / with open

I/O

Pythonic conditions

Control flow

Function tools / closures / partial / cache

Functions

Decorators (function, parametrised, stacked, class)

Functions

GoF patterns (Singleton, Factory, Strategy, Observer, Adapter, Facade)

OOP

Middleware (plain, WSGI / ASGI)

Frameworks

Zen#

The Zen of Python (import this) is genuinely operational guidance, not folklore.

  • Explicit is better than implicit. Pass dependencies in.

  • Flat is better than nested. Early return, guard clauses.

  • Errors should never pass silently. Don’t except: pass.

  • In the face of ambiguity, refuse the temptation to guess.

  • There should be one obvious way to do it. When the standard library has it, use it.

Anti-patterns#

The patterns that look right but bite later. Each row is the form, the reason it bites, and the fix.

Anti-pattern

Why and fix

Mutable default argument

def f(xs=[]): shares the same list across every call. Use xs: list | None = None and replace inside the body with xs = xs if xs is not None else [].

Bare except:

Catches KeyboardInterrupt and SystemExit too. Catch Exception or a specific class.

except Exception: pass

Silently eats errors. Log at minimum; re-raise from a wrapper that adds context.

Monkey-patching at import time

Side-effects on import surprise users and make tests order-dependent. Patch explicitly with unittest.mock.

from module import *

Pollutes the namespace and breaks tooling. Import what you use.

Singleton via global state

Pretends to be encapsulated but is global state. A module-level cached value is more honest.

Long argument lists

Past 5–6 parameters, group with a @dataclass or a config object.

Stringly-typed APIs

role="admin" invites typos. Use an Enum or Literal["admin", "user"].

Comparing with == None

Works but reads as a junior tell. Use is None.

Catching and re-raising without context

raise loses the cause. Use raise X from e to chain.

References#