Python patterns
/SKILL> This skill provides comprehensive Python patterns extending common design principles with Python-specific idioms.
--- name: python-patterns description: > Python-specific design patterns and best practices including protocols, dataclasses, context managers, decorators, async/await, type hints, and package organization. Use when working with Python code to apply Pythonic patterns. metadata: origin: ECC globs: ["*/.py", "*/.pyi"] --- # Python Patterns > This skill provides comprehensive Python patterns extending common design principles with Python-specific idioms. ## Protocol (Duck Typing) Use Protocol for structural subtyping (duck typing with type hints): ``python from typing import Protocol class Repository(Protocol): def find_by_id(self, id: str) -> dict | None: ... def save(self, entity: dict) -> dict: ... # Any class with these methods satisfies the protocol class UserRepository: def find_by_id(self, id: str) -> dict | None: # implementation pass def save(self, entity: dict) -> dict: # implementation pass def process_entity(repo: Repository, id: str) -> None: entity = repo.find_by_id(id) # ... process ` **Benefits:** - Type safety without inheritance - Flexible, loosely coupled code - Easy testing and mocking ## Dataclasses as DTOs Use dataclass for data transfer objects and value objects: `python from dataclasses import dataclass, field from typing import Optional @dataclass class CreateUserRequest: name: str email: str age: Optional[int] = None tags: list[str] = field(default_factory=list) @dataclass(frozen=True) class User: """Immutable user entity""" id: str name: str email: str ` **Features:** - Auto-generated init, repr, eq - frozen=True for immutability - field() for complex defaults - Type hints for validation ## Context Managers Use context managers (with statement) for resource management: `python from contextlib import contextmanager from typing import Generator @contextmanager def database_transaction(db) -> Generator[None, None, None]: """Context manager for database transactions""" try: yield db.commit() except Exception: db.rollback() raise # Usage with database_transaction(db): db.execute("INSERT INTO users ...") ` **Class-based context manager:** `python class FileProcessor: def __init__(self, filename: str): self.filename = filename self.file = None def __enter__(self): self.file = open(self.filename, 'r') return self.file def __exit__(self, exc_type, exc_val, exc_tb): if self.file: self.file.close() return False # Don't suppress exceptions ` ## Generators Use generators for lazy evaluation and memory-efficient iteration: `python def read_large_file(filename: str): """Generator for reading large files line by line""" with open(filename, 'r') as f: for line in f: yield line.strip() # Memory-efficient processing for line in read_large_file('huge.txt'): process(line) ` **Generator expressions:** `python # Instead of list comprehension squares = (x**2 for x in range(1000000)) # Lazy evaluation # Pipeline pattern numbers = (x for x in range(100)) evens = (x for x in numbers if x % 2 == 0) squares = (x**2 for x in evens) ` ## Decorators ### Function Decorators `python from functools import wraps import time def timing(func): """Decorator to measure execution time""" @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f"{func.__name__} took {end - start:.2f}s") return result return wrapper @timing def slow_function(): time.sleep(1) ` ### Class Decorators `python def singleton(cls): """Decorator to make a class a singleton""" instances = {} @wraps(cls) def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class Config: pass ` ## Async/Await ### Async Functions `python import asyncio from typing import List async def fetch_user(user_id: str) -> dict: """Async function for I/O-bound operations""" await asyncio.sleep(0.1) # Simulate network call return {"id": user_id, "name": "Alice"} async def fetch_all_users(user_ids: List[str]) -> List[dict]: """Concurrent execution with asyncio.gather""" tasks = [fetch_user(uid) for uid in user_ids] return await asyncio.gather(*tasks) # Run async code asyncio.run(fetch_all_users(["1", "2", "3"])) ` ### Async Context Managers `python class AsyncDatabase: async def __aenter__(self): await self.connect() return self async def __aexit__(self, exc_type, exc_val, exc_tb): await self.disconnect() async with AsyncDatabase() as db: await db.query("SELECT * FROM users") `` ## Type