Agent skill
python-design-patterns
This skill should be used when the user asks about "design patterns", "SOLID principles", "factory pattern", "strategy pattern", "observer pattern", "composition vs inheritance", "Pythonic design", "singleton alternatives", "anti-patterns", "dependency injection", or needs guidance on applying Gang of Four patterns idiomatically in Python.
Install this agent skill to your Project
npx add-skill https://github.com/WorldCentralKitchen/python-dev-framework/tree/main/skills/design-patterns
SKILL.md
Python Design Patterns
Pythonic adaptations of GoF patterns, SOLID principles, and anti-patterns to avoid.
"Modern Python simply avoids the problems that the old design patterns were meant to solve." — Brandon Rhodes, PyCon 2025
Prerequisites: from __future__ import annotations, collections.abc for Callable/Iterator, structlog for logging.
Pattern Decision Table
| Need | Pattern | Python Idiom |
|---|---|---|
| Multiple creation strategies | Factory | Function or @classmethod |
| Complex object, many options | Builder | dataclass + replace() |
| Interchangeable algorithms | Strategy | Pass Callable |
| Event notification | Observer | Callback list |
| Lazy sequences | Iterator | Generator (yield) |
| Tree structures | Composite | Recursive dataclass |
| Memory optimization | Flyweight | __slots__, lru_cache |
| Interface conversion | Adapter | Wrapper class |
| Cross-cutting concerns | Decorator | @decorator |
| State machines | State | Dict mapping or match |
| Shared configuration | Global Object | Module-level instance |
| Callbacks with state | Prebound Method | obj.method, partial |
| None is valid value | Sentinel | _MISSING = object() |
SOLID Quick Reference
| Principle | Violation Sign | Fix |
|---|---|---|
| Single Responsibility | "Manager" class | Split into focused classes |
| Open-Closed | if/elif on types |
Dict of handlers + Protocol |
| Liskov Substitution | NotImplementedError |
Composition over inheritance |
| Interface Segregation | Unused interface methods | Small Protocol classes |
| Dependency Inversion | self.db = PostgresDB() |
Constructor injection |
Anti-Patterns
| Anti-Pattern | Why Bad | Pythonic Alternative |
|---|---|---|
| Singleton class | Modules ARE singletons | Module-level instance |
| Deep inheritance | Coupling, diamond problem | Composition + Protocol |
| Java getters/setters | Boilerplate | Direct attrs, @property |
| God Object | Untestable, SRP violation | Focused services |
| Method without self | Unnecessary class | Module-level function |
| Premature patterns | Over-engineering | YAGNI - add when needed |
Key Patterns
Factory & Strategy
# Factory: function returning instance
def create_connection(db_type: str) -> Connection:
return {"postgres": PostgresConn, "sqlite": SQLiteConn}[db_type]()
# Strategy: pass functions, not strategy objects
def calculate_total(items: list[Item], pricing: Callable[[float], float]) -> float:
return sum(pricing(i.price) for i in items)
Observer & Decorator
# Observer: callback list
@dataclass
class EventEmitter:
_listeners: dict[str, list[Callable]] = field(default_factory=dict)
def on(self, event: str, fn: Callable) -> None:
self._listeners.setdefault(event, []).append(fn)
def emit(self, event: str, *args) -> None:
for fn in self._listeners.get(event, []): fn(*args)
# Decorator: @wraps for cross-cutting concerns
def timing(func):
@wraps(func)
def wrapper(*a, **kw):
start = perf_counter()
result = func(*a, **kw)
log.info("timing", elapsed=perf_counter() - start)
return result
return wrapper
Global Object & Sentinel
# Global Object: module-level instance (not singleton class)
_config: Config | None = None
def get_config() -> Config:
global _config
if _config is None: _config = Config.from_env()
return _config
# Sentinel: distinguish None from "not provided"
_MISSING = object()
def get(key: str, default: object = _MISSING) -> object:
if (v := cache.get(key)) is not None: return v
if default is _MISSING: raise KeyError(key)
return default
Reference Files
| File | Content |
|---|---|
references/patterns.md |
All GoF patterns with examples |
references/solid-anti.md |
SOLID principles + anti-patterns |
references/python-idioms.md |
Global Object, Prebound Method, Sentinel |
Related
- ADR-014 - Design decisions
- ADR-013 - Immutability patterns
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
python-development-standards
This skill should be used when the user asks about "Python code style", "type hints", "structlog logging", "how to log", "code organization", "testing patterns", "error handling", or needs guidance on Python development best practices, project conventions, or coding standards for this project.
plugin-versioning
Guide for versioning and releasing Claude Code plugins. Covers semantic versioning, CHANGELOG maintenance, and the automated release workflow.
handoff
Compact the current conversation into a handoff document for another agent to pick up.
obsidian-vault
Search, create, and manage notes in the Obsidian vault with wikilinks and index notes. Use when user wants to find, create, or organize notes in Obsidian.
scaffold-exercises
Create exercise directory structures with sections, problems, solutions, and explainers that pass linting. Use when user wants to scaffold exercises, create exercise stubs, or set up a new course section.
edit-article
Edit and improve articles by restructuring sections, improving clarity, and tightening prose. Use when user wants to edit, revise, or improve an article draft.
Didn't find tool you were looking for?