Patterns Python
/SKILL> Cette compétence fournit des modèles Python complets qui étendent les principes de conception communs avec des idiomes spécifiques à Python.
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):
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)
# ... processBenefits:
- Type safety without inheritance
- Flexible, loosely coupled code
- Easy testing and mocking
Dataclasses as DTOs
Use dataclass for data transfer objects and value objects:
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: strFeatures:
- Auto-generated
__init__,__repr__,__eq__ frozen=Truefor immutabilityfield()for complex defaults- Type hints for validation
Context Managers
Use context managers (with statement) for resource management:
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:
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 exceptionsGenerators
Use generators for lazy evaluation and memory-efficient iteration:
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:
# 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
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
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:
passAsync/Await
Async Functions
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
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")