Python Patterns

affaan-m/ECC/.kiro/skills/python-patterns

by affaan-mef648e01899ba3e8dc6371642deaaf64b4477775No license275K starsListed Oct 9, 2026Updated Oct 9, 2026Repository updated 4 days ago

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.

Instructions onlySoftware Development
AI-generated overview

Reference guide to Pythonic design patterns, type hints, async, and package organization for writing Python code.

What it does
Provides a reference of Python-specific design patterns and idioms, covering Protocol-based duck typing, dataclasses, context managers, generators, decorators, async/await, advanced type hints, dependency injection, package layout, error handling, properties, and functional composition. Each pattern is illustrated with short code examples and notes on benefits. It produces guidance rather than files or runnable output.
When to use it
Use when designing Python APIs, packages, or project structures, implementing async or concurrent systems, writing type-safe or Pythonic code, or refactoring an existing Python codebase.
Requirements
No tools, packages, or credentials required; it is an instructions-only skill with no scripts. Examples reference standard-library modules such as typing, dataclasses, contextlib, functools, and asyncio.

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 protocolclass 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, fieldfrom typing import Optional
@dataclassclass 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 contextmanagerfrom typing import Generator
@contextmanagerdef database_transaction(db) -> Generator[None, None, None]:    """Context manager for database transactions"""    try:        yield        db.commit()    except Exception:        db.rollback()        raise
# Usagewith 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 processingfor line in read_large_file('huge.txt'):    process(line)

Generator expressions:

python
# Instead of list comprehensionsquares = (x**2 for x in range(1000000))  # Lazy evaluation
# Pipeline patternnumbers = (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 wrapsimport 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
@timingdef 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
@singletonclass Config:    pass

Async/Await

Async Functions

python
import asynciofrom 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 codeasyncio.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 Hints

Advanced Type Hints

python
from typing import TypeVar, Generic, Callable, ParamSpec, Concatenate
T = TypeVar('T')P = ParamSpec('P')
class Repository(Generic[T]):    """Generic repository pattern"""    def __init__(self, entity_type: type[T]):        self.entity_type = entity_type
    def find_by_id(self, id: str) -> T | None:        # implementation        pass
# Type-safe decoratordef log_call(func: Callable[P, T]) -> Callable[P, T]:    @wraps(func)    def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:        print(f"Calling {func.__name__}")        return func(*args, **kwargs)    return wrapper

Union Types (Python 3.10+)

python
def process(value: str | int | None) -> str:    match value:        case str():            return value.upper()        case int():            return str(value)        case None:            return "empty"

Dependency Injection

Constructor Injection

python
class UserService:    def __init__(        self,        repository: Repository,        logger: Logger,        cache: Cache | None = None    ):        self.repository = repository        self.logger = logger        self.cache = cache
    def get_user(self, user_id: str) -> User | None:        if self.cache:            cached = self.cache.get(user_id)            if cached:                return cached
        user = self.repository.find_by_id(user_id)        if user and self.cache:            self.cache.set(user_id, user)
        return user

Package Organization

Project Structure

project/├── src/│   └── mypackage/│       ├── __init__.py│       ├── domain/          # Business logic│       │   ├── __init__.py│       │   └── models.py│       ├── services/        # Application services│       │   ├── __init__.py│       │   └── user_service.py│       └── infrastructure/  # External dependencies│           ├── __init__.py│           └── database.py├── tests/│   ├── unit/│   └── integration/├── pyproject.toml└── README.md

Module Exports

python
# __init__.pyfrom .models import User, Productfrom .services import UserService
__all__ = ['User', 'Product', 'UserService']

Error Handling

Custom Exceptions

python
class DomainError(Exception):    """Base exception for domain errors"""    pass
class UserNotFoundError(DomainError):    """Raised when user is not found"""    def __init__(self, user_id: str):        self.user_id = user_id        super().__init__(f"User {user_id} not found")
class ValidationError(DomainError):    """Raised when validation fails"""    def __init__(self, field: str, message: str):        self.field = field        self.message = message        super().__init__(f"{field}: {message}")

Exception Groups (Python 3.11+)

python
try:    # Multiple operations    passexcept* ValueError as eg:    # Handle all ValueError instances    for exc in eg.exceptions:        print(f"ValueError: {exc}")except* TypeError as eg:    # Handle all TypeError instances    for exc in eg.exceptions:        print(f"TypeError: {exc}")

Property Decorators

python
class User:    def __init__(self, name: str):        self._name = name        self._email = None
    @property    def name(self) -> str:        """Read-only property"""        return self._name
    @property    def email(self) -> str | None:        return self._email
    @email.setter    def email(self, value: str) -> None:        if '@' not in value:            raise ValueError("Invalid email")        self._email = value

Functional Programming

Higher-Order Functions

python
from functools import reducefrom typing import Callable, TypeVar
T = TypeVar('T')U = TypeVar('U')
def pipe(*functions: Callable) -> Callable:    """Compose functions left to right"""    def inner(arg):        return reduce(lambda x, f: f(x), functions, arg)    return inner
# Usageprocess = pipe(    str.strip,    str.lower,    lambda s: s.replace(' ', '_'))result = process("  Hello World  ")  # "hello_world"

When to Use This Skill

  • Designing Python APIs and packages
  • Implementing async/concurrent systems
  • Structuring Python projects
  • Writing Pythonic code
  • Refactoring Python codebases
  • Type-safe Python development

Source and attribution

Source:affaan-m/ECCin.kiro/skills/python-patternsat commitef648e0

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal