# Python Patterns

> When to activate: general Python code, idiomatic Python, data structures, comprehensions, generators, context managers, decorators

- Skill: `mattakushi432/python-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/python-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/python-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/python-patterns

---


# Python Patterns

## Core Idioms

### Prefer comprehensions over loops for transformations
```python
# Good
evens = [x for x in range(10) if x % 2 == 0]
squared = {k: v**2 for k, v in data.items()}

# Bad
evens = []
for x in range(10):
    if x % 2 == 0:
        evens.append(x)
```

### Use generators for large sequences
```python
def read_chunks(file_path: Path, size: int = 8192) -> Generator[bytes, None, None]:
    with open(file_path, "rb") as f:
        while chunk := f.read(size):
            yield chunk
```

### Context managers for resource management
```python
from contextlib import contextmanager

@contextmanager
def managed_connection(url: str):
    conn = connect(url)
    try:
        yield conn
    finally:
        conn.close()
```

### Dataclasses for structured data
```python
from dataclasses import dataclass, field
from datetime import datetime

@dataclass(frozen=True)
class User:
    id: int
    name: str
    email: str
    created_at: datetime = field(default_factory=datetime.utcnow)
```

### Named tuples for lightweight value objects
```python
from typing import NamedTuple

class Point(NamedTuple):
    x: float
    y: float
    
    def distance(self, other: "Point") -> float:
        return ((self.x - other.x)**2 + (self.y - other.y)**2) ** 0.5
```

## Error Handling

### Specific exceptions, not bare except
```python
# Good
try:
    result = parse_config(path)
except FileNotFoundError:
    logger.warning("Config not found, using defaults")
    result = DEFAULT_CONFIG
except json.JSONDecodeError as e:
    raise ConfigError(f"Invalid JSON in config: {e}") from e

# Bad
try:
    result = parse_config(path)
except:  # catches SystemExit, KeyboardInterrupt, etc.
    result = {}
```

### Custom exception hierarchy
```python
class AppError(Exception):
    """Base exception for this application."""

class ValidationError(AppError):
    def __init__(self, field: str, message: str) -> None:
        self.field = field
        super().__init__(f"{field}: {message}")

class NotFoundError(AppError):
    pass
```

## Type Annotations

```python
from typing import TypeVar, Callable, Awaitable
from collections.abc import Sequence

T = TypeVar("T")

def first(items: Sequence[T], predicate: Callable[[T], bool]) -> T | None:
    return next((item for item in items if predicate(item)), None)

# Use | None (3.10+) not Optional[T]
def find_user(user_id: int) -> User | None: ...

# Use type aliases for complex types
JsonDict = dict[str, "JsonValue"]
JsonValue = str | int | float | bool | None | list["JsonValue"] | JsonDict
```

## Common Anti-Patterns

- **Mutable default arguments**: `def f(items=[])` → use `items: list | None = None`
- **Shadowing builtins**: `list = [...]`, `id = ...`
- **String concatenation in loops**: use `"".join(parts)` or f-strings
- **`is` for value comparison**: `x is 1` → use `==`
- **Not using `__slots__`** on hot dataclasses in tight loops

