AgentSkillsCN

Python Patterns

Python 设计模式

SKILL.md

Python Patterns Skill

Write Pythonic, clean, and maintainable Python code

🎯 PRINCIPLES

1. The Zen of Python

python
import this
# Beautiful is better than ugly.
# Explicit is better than implicit.
# Simple is better than complex.
# Readability counts.
# There should be one-- and preferably only one --obvious way to do it.

2. PEP 8 Quick Reference

  • 4 spaces for indentation
  • Max line length: 88-120 characters
  • snake_case for functions/variables
  • PascalCase for classes
  • UPPER_SNAKE for constants
  • Two blank lines between top-level definitions

3. Type Hints (PEP 484)

python
from typing import Optional, Union, TypeVar, Generic
from collections.abc import Callable, Iterable

def greet(name: str) -> str:
    return f"Hello, {name}"

def process(items: list[int]) -> dict[str, int]:
    return {"sum": sum(items), "count": len(items)}

# Optional = Union[X, None]
def find_user(id: int) -> Optional[User]:
    ...

# TypeVar for generics
T = TypeVar('T')
def first(items: list[T]) -> T | None:
    return items[0] if items else None

📘 COMPREHENSIONS

List Comprehension

python
# ✅ Good - Simple transformation
squares = [x**2 for x in range(10)]
names = [user.name for user in users]

# ✅ Good - With condition
evens = [x for x in numbers if x % 2 == 0]
adults = [u for u in users if u.age >= 18]

# ✅ Good - Nested (flatten)
flat = [item for sublist in nested for item in sublist]

# ❌ Bad - Too complex
# Use regular loop instead
result = [
    transform(x) for x in items 
    if condition(x) 
    for y in x.children 
    if other_condition(y)
]

Dict Comprehension

python
# Create dict from list
user_by_id = {u.id: u for u in users}

# Swap keys and values
inverted = {v: k for k, v in original.items()}

# Filter dict
filtered = {k: v for k, v in data.items() if v > 0}

Set Comprehension

python
# Unique values
unique_names = {user.name.lower() for user in users}

🎨 DECORATORS

Basic Decorator

python
from functools import wraps
from typing import Callable, TypeVar, ParamSpec

P = ParamSpec('P')
R = TypeVar('R')

def log_calls(func: Callable[P, R]) -> Callable[P, R]:
    @wraps(func)  # Preserves function metadata
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
        print(f"Calling {func.__name__}")
        result = func(*args, **kwargs)
        print(f"Finished {func.__name__}")
        return result
    return wrapper

@log_calls
def process_data(data: list[int]) -> int:
    return sum(data)

Decorator with Arguments

python
def retry(max_attempts: int = 3, delay: float = 1.0):
    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 as e:
                    if attempt == max_attempts - 1:
                        raise
                    time.sleep(delay)
            raise RuntimeError("Should not reach here")
        return wrapper
    return decorator

@retry(max_attempts=5, delay=0.5)
def fetch_data(url: str) -> dict:
    ...

Class Decorator

python
def singleton(cls):
    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 DatabaseConnection:
    ...

📦 DATACLASSES

Basic Dataclass

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):
        self.email = self.email.lower()

Frozen (Immutable)

python
@dataclass(frozen=True)
class Point:
    x: float
    y: float
    
    def distance_to(self, other: 'Point') -> float:
        return ((self.x - other.x)**2 + (self.y - other.y)**2)**0.5

With Slots (Memory Efficient)

python
@dataclass(slots=True)
class LargeDataset:
    values: list[float]
    labels: list[str]

Field Options

python
@dataclass
class Config:
    # Required field
    name: str
    
    # Default value
    debug: bool = False
    
    # Computed default
    timestamp: float = field(default_factory=time.time)
    
    # Exclude from repr
    secret: str = field(repr=False)
    
    # Exclude from comparison
    cache: dict = field(compare=False, default_factory=dict)

🔄 GENERATORS

Generator Function

python
def read_large_file(filepath: str):
    """Memory-efficient file reading."""
    with open(filepath) as f:
        for line in f:
            yield line.strip()

# Usage
for line in read_large_file("huge.txt"):
    process(line)

Generator Expression

python
# Lazy evaluation - doesn't create list in memory
sum_squares = sum(x**2 for x in range(1_000_000))

# Process large data lazily
large_data = (process(x) for x in huge_iterator)

Yield From

python
def flatten(nested: list[list[int]]) -> Iterator[int]:
    for sublist in nested:
        yield from sublist

# Equivalent to:
# for item in sublist:
#     yield item

📋 CONTEXT MANAGERS

Using contextlib

python
from contextlib import contextmanager, asynccontextmanager

@contextmanager
def timer(name: str):
    start = time.perf_counter()
    try:
        yield
    finally:
        elapsed = time.perf_counter() - start
        print(f"{name} took {elapsed:.3f}s")

with timer("Processing"):
    do_heavy_work()

Class-based Context Manager

python
class DatabaseTransaction:
    def __init__(self, connection):
        self.connection = connection
    
    def __enter__(self):
        self.connection.begin()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is None:
            self.connection.commit()
        else:
            self.connection.rollback()
        return False  # Don't suppress exceptions

🎯 PATTERN MATCHING (3.10+)

python
def process_command(command: dict) -> str:
    match command:
        case {"action": "create", "name": name}:
            return f"Creating {name}"
        
        case {"action": "delete", "id": int() as id}:
            return f"Deleting item {id}"
        
        case {"action": "update", "id": id, **rest}:
            return f"Updating {id} with {rest}"
        
        case {"action": action}:
            return f"Unknown action: {action}"
        
        case _:
            return "Invalid command"

# With types
def handle_response(response: tuple) -> None:
    match response:
        case (200, body):
            print(f"Success: {body}")
        case (404, _):
            print("Not found")
        case (code, _) if code >= 500:
            print("Server error")

⚠️ ANTI-PATTERNS

❌ Mutable Default Arguments

python
# ❌ BAD - Shared list between calls!
def append_to(item, lst=[]):
    lst.append(item)
    return lst

# ✅ GOOD
def append_to(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

❌ Bare Except

python
# ❌ BAD - Catches everything including KeyboardInterrupt
try:
    risky_operation()
except:
    pass

# ✅ GOOD - Be specific
try:
    risky_operation()
except (ValueError, TypeError) as e:
    logger.error(f"Operation failed: {e}")

❌ Using type() for Type Checking

python
# ❌ BAD - Doesn't handle inheritance
if type(obj) == SomeClass:
    ...

# ✅ GOOD
if isinstance(obj, SomeClass):
    ...

❌ String Concatenation in Loops

python
# ❌ BAD - O(n²) complexity
result = ""
for item in items:
    result += str(item)

# ✅ GOOD - O(n) complexity
result = "".join(str(item) for item in items)

🔧 MODERN PYTHON FEATURES

Walrus Operator (:=) - 3.8+

python
# Assign and use in one expression
if (n := len(items)) > 10:
    print(f"Too many items: {n}")

# In comprehensions
valid = [y for x in data if (y := validate(x)) is not None]

# In while loops
while (line := file.readline()):
    process(line)

Union Types (|) - 3.10+

python
# Old style
def process(value: Union[int, str]) -> Optional[Result]:
    ...

# New style (3.10+)
def process(value: int | str) -> Result | None:
    ...

F-strings Debug (=) - 3.8+

python
x = 10
y = 20
print(f"{x=}, {y=}")  # Output: x=10, y=20
print(f"{x + y = }")  # Output: x + y = 30

📎 QUICK REFERENCE

PatternWhen to Use
List ComprehensionTransform/filter sequences
Dict ComprehensionBuild dicts from iterables
GeneratorProcess large data lazily
DecoratorCross-cutting concerns (logging, timing)
DataclassData containers with methods
Context ManagerResource management (files, locks)
Pattern MatchingComplex conditional logic

🔗 RELATED SKILLS