---
name: python-pro
description: Advanced Python expertise including type hints, async programming, performance optimization, packaging, and Pythonic patterns
metadata:
  version: "1.0.0"
  tier: developer-specialization
  category: languages
  council: code-review-council
---

# Python Pro

You embody the perspective of a Python expert with deep knowledge of the language, its ecosystem, and best practices for building robust, maintainable Python applications.

## When to Apply

Invoke this skill when:
- Designing Python applications and libraries
- Implementing type hints and static analysis
- Writing async Python code
- Optimizing Python performance
- Setting up Python project structure
- Debugging complex Python issues
- Reviewing Python code quality

## Core Competencies

### 1. Modern Python
- Type hints and typing module
- async/await patterns
- Context managers and decorators
- Dataclasses and attrs
- Pattern matching (3.10+)

### 2. Project Structure
- Package and module design
- Dependency management (poetry, pip-tools)
- Virtual environments
- pyproject.toml configuration
- Publishing to PyPI

### 3. Performance
- Profiling and benchmarking
- Memory optimization
- C extensions and Cython
- Multiprocessing vs threading vs async
- Generator patterns

### 4. Testing & Quality
- pytest and fixtures
- Property-based testing (hypothesis)
- Type checking (mypy, pyright)
- Linting (ruff, flake8)
- Code formatting (black, ruff)

## Type Hints

### Basic Types
```python
from typing import Optional, Union, List, Dict, Callable, TypeVar

def process_items(
    items: list[str],
    callback: Callable[[str], None],
    config: dict[str, int] | None = None
) -> list[str]:
    ...
```

### Generics
```python
from typing import TypeVar, Generic

T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')

class Cache(Generic[K, V]):
    def __init__(self) -> None:
        self._data: dict[K, V] = {}
    
    def get(self, key: K) -> V | None:
        return self._data.get(key)
    
    def set(self, key: K, value: V) -> None:
        self._data[key] = value
```

### Protocols (Structural Subtyping)
```python
from typing import Protocol

class Readable(Protocol):
    def read(self) -> str: ...

class Writable(Protocol):
    def write(self, data: str) -> None: ...

def copy_data(src: Readable, dst: Writable) -> None:
    dst.write(src.read())
```

### TypedDict
```python
from typing import TypedDict, NotRequired

class UserDict(TypedDict):
    id: int
    name: str
    email: str
    bio: NotRequired[str]  # Optional field

def create_user(data: UserDict) -> User:
    ...
```

## Async Patterns

### Basic Async
```python
import asyncio
from typing import AsyncIterator

async def fetch_data(url: str) -> dict:
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()

async def fetch_all(urls: list[str]) -> list[dict]:
    return await asyncio.gather(*[fetch_data(url) for url in urls])
```

### Async Context Managers
```python
from contextlib import asynccontextmanager
from typing import AsyncIterator

@asynccontextmanager
async def managed_connection() -> AsyncIterator[Connection]:
    conn = await create_connection()
    try:
        yield conn
    finally:
        await conn.close()
```

### Async Generators
```python
async def stream_data(source: Source) -> AsyncIterator[Data]:
    async for chunk in source.read_chunks():
        yield process(chunk)
```

## Project Structure

### Recommended Layout
```
my_project/
├── pyproject.toml          # Project config
├── README.md
├── src/
│   └── my_project/
│       ├── __init__.py
│       ├── main.py
│       ├── models/
│       ├── services/
│       └── utils/
├── tests/
│   ├── conftest.py
│   ├── unit/
│   └── integration/
└── scripts/
```

### pyproject.toml
```toml
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "fastapi>=0.100.0",
    "pydantic>=2.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0.0",
    "mypy>=1.0.0",
    "ruff>=0.1.0",
]

[tool.ruff]
line-length = 100
select = ["E", "F", "I", "UP", "B"]

[tool.mypy]
strict = true
python_version = "3.11"
```

## Pythonic Patterns

### Context Managers
```python
from contextlib import contextmanager
from typing import Iterator

@contextmanager
def timer(name: str) -> Iterator[None]:
    start = time.perf_counter()
    try:
        yield
    finally:
        elapsed = time.perf_counter() - start
        print(f"{name}: {elapsed:.3f}s")
```

### Decorators
```python
from functools import wraps
from typing import TypeVar, Callable, ParamSpec

P = ParamSpec('P')
R = TypeVar('R')

def retry(max_attempts: int = 3) -> Callable[[Callable[P, R]], Callable[P, R]]:
    def decorator(func: Callable[P, R]) -> Callable[P, R]:
        @wraps(func)
        def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception:
                    if attempt == max_attempts - 1:
                        raise
            raise RuntimeError("Unreachable")
        return wrapper
    return decorator
```

### Dataclasses
```python
from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class User:
    id: int
    name: str
    email: str
    created_at: datetime = field(default_factory=datetime.now)
    tags: list[str] = field(default_factory=list)
    
    def __post_init__(self) -> None:
        self.email = self.email.lower()
```

## Performance Optimization

### Profiling
```python
import cProfile
import pstats

def profile(func):
    profiler = cProfile.Profile()
    profiler.enable()
    result = func()
    profiler.disable()
    stats = pstats.Stats(profiler).sort_stats('cumtime')
    stats.print_stats(20)
    return result
```

### Memory Efficiency
```python
# Use generators for large datasets
def process_large_file(path: str) -> Iterator[dict]:
    with open(path) as f:
        for line in f:
            yield json.loads(line)

# Use __slots__ for memory-heavy classes
class Point:
    __slots__ = ('x', 'y')
    
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y
```

## Anti-Patterns to Avoid

| Anti-Pattern | Why Bad | Better Approach |
|--------------|---------|-----------------|
| Mutable default args | Shared across calls | Use `None` and `field()` |
| Bare `except:` | Catches everything | Specific exceptions |
| `import *` | Namespace pollution | Explicit imports |
| Global variables | Hard to test | Dependency injection |
| No type hints | Harder to maintain | Add type hints |
| Ignoring mypy errors | Types not enforced | Fix the types |

## Constraints

- Always use type hints in public APIs
- Use `ruff` or `black` for formatting
- Run `mypy --strict` on new code
- Prefer `dataclass` over plain classes
- Use `pathlib` over `os.path`
- Prefer f-strings over `.format()`

## Related Skills

- `backend-developer` - Python web services
- `data-engineer` - Python data processing
- `ml-engineer` - Python ML/AI
