From python-dev-framework
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.
npx claudepluginhub worldcentralkitchen/python-dev-frameworkThis skill uses the workspace's default tool permissions.
Pythonic adaptations of GoF patterns, SOLID principles, and anti-patterns to avoid.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
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.
| 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() |
| 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-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 |
# 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: 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: 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
| 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 |