Install
Terminal · npx$
npx skills add https://github.com/affaan-m/everything-claude-code --skill python-patternsWorks with Paperclip
How Python Patterns fits into a Paperclip company.
Python Patterns drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.
S
SaaS FactoryPaired
Pre-configured AI company — 18 agents, 18 skills, one-time purchase.
$27$59
Explore packSource file
SKILL.md750 linesExpandCollapse
---name: python-patternsdescription: Pythonic idioms, PEP 8 standards, type hints, and best practices for building robust, efficient, and maintainable Python applications.origin: ECC--- # Python Development Patterns Idiomatic Python patterns and best practices for building robust, efficient, and maintainable applications. ## When to Activate - Writing new Python code- Reviewing Python code- Refactoring existing Python code- Designing Python packages/modules ## Core Principles ### 1. Readability Counts Python prioritizes readability. Code should be obvious and easy to understand. ```python# Good: Clear and readabledef get_active_users(users: list[User]) -> list[User]: """Return only active users from the provided list.""" return [user for user in users if user.is_active] # Bad: Clever but confusingdef get_active_users(u): return [x for x in u if x.a]``` ### 2. Explicit is Better Than Implicit Avoid magic; be clear about what your code does. ```python# Good: Explicit configurationimport logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') # Bad: Hidden side effectsimport some_modulesome_module.setup() # What does this do?``` ### 3. EAFP - Easier to Ask Forgiveness Than Permission Python prefers exception handling over checking conditions. ```python# Good: EAFP styledef get_value(dictionary: dict, key: str) -> Any: try: return dictionary[key] except KeyError: return default_value # Bad: LBYL (Look Before You Leap) styledef get_value(dictionary: dict, key: str) -> Any: if key in dictionary: return dictionary[key] else: return default_value``` ## Type Hints ### Basic Type Annotations ```pythonfrom typing import Optional, List, Dict, Any def process_user( user_id: str, data: Dict[str, Any], active: bool = True) -> Optional[User]: """Process a user and return the updated User or None.""" if not active: return None return User(user_id, data)``` ### Modern Type Hints (Python 3.9+) ```python# Python 3.9+ - Use built-in typesdef process_items(items: list[str]) -> dict[str, int]: return {item: len(item) for item in items} # Python 3.8 and earlier - Use typing modulefrom typing import List, Dict def process_items(items: List[str]) -> Dict[str, int]: return {item: len(item) for item in items}``` ### Type Aliases and TypeVar ```pythonfrom typing import TypeVar, Union # Type alias for complex typesJSON = Union[dict[str, Any], list[Any], str, int, float, bool, None] def parse_json(data: str) -> JSON: return json.loads(data) # Generic typesT = TypeVar('T') def first(items: list[T]) -> T | None: """Return the first item or None if list is empty.""" return items[0] if items else None``` ### Protocol-Based Duck Typing ```pythonfrom typing import Protocol class Renderable(Protocol): def render(self) -> str: """Render the object to a string.""" def render_all(items: list[Renderable]) -> str: """Render all items that implement the Renderable protocol.""" return "\n".join(item.render() for item in items)``` ## Error Handling Patterns ### Specific Exception Handling ```python# Good: Catch specific exceptionsdef load_config(path: str) -> Config: try: with open(path) as f: return Config.from_json(f.read()) except FileNotFoundError as e: raise ConfigError(f"Config file not found: {path}") from e except json.JSONDecodeError as e: raise ConfigError(f"Invalid JSON in config: {path}") from e # Bad: Bare exceptdef load_config(path: str) -> Config: try: with open(path) as f: return Config.from_json(f.read()) except: return None # Silent failure!``` ### Exception Chaining ```pythondef process_data(data: str) -> Result: try: parsed = json.loads(data) except json.JSONDecodeError as e: # Chain exceptions to preserve the traceback raise ValueError(f"Failed to parse data: {data}") from e``` ### Custom Exception Hierarchy ```pythonclass AppError(Exception): """Base exception for all application errors.""" pass class ValidationError(AppError): """Raised when input validation fails.""" pass class NotFoundError(AppError): """Raised when a requested resource is not found.""" pass # Usagedef get_user(user_id: str) -> User: user = db.find_user(user_id) if not user: raise NotFoundError(f"User not found: {user_id}") return user``` ## Context Managers ### Resource Management ```python# Good: Using context managersdef process_file(path: str) -> str: with open(path, 'r') as f: return f.read() # Bad: Manual resource managementdef process_file(path: str) -> str: f = open(path, 'r') try: return f.read() finally: f.close()``` ### Custom Context Managers ```pythonfrom contextlib import contextmanager @contextmanagerdef timer(name: str): """Context manager to time a block of code.""" start = time.perf_counter() yield elapsed = time.perf_counter() - start print(f"{name} took {elapsed:.4f} seconds") # Usagewith timer("data processing"): process_large_dataset()``` ### Context Manager Classes ```pythonclass DatabaseTransaction: def __init__(self, connection): self.connection = connection def __enter__(self): self.connection.begin_transaction() 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 # Usagewith DatabaseTransaction(conn): user = conn.create_user(user_data) conn.create_profile(user.id, profile_data)``` ## Comprehensions and Generators ### List Comprehensions ```python# Good: List comprehension for simple transformationsnames = [user.name for user in users if user.is_active] # Bad: Manual loopnames = []for user in users: if user.is_active: names.append(user.name) # Complex comprehensions should be expanded# Bad: Too complexresult = [x * 2 for x in items if x > 0 if x % 2 == 0] # Good: Use a generator functiondef filter_and_transform(items: Iterable[int]) -> list[int]: result = [] for x in items: if x > 0 and x % 2 == 0: result.append(x * 2) return result``` ### Generator Expressions ```python# Good: Generator for lazy evaluationtotal = sum(x * x for x in range(1_000_000)) # Bad: Creates large intermediate listtotal = sum([x * x for x in range(1_000_000)])``` ### Generator Functions ```pythondef read_large_file(path: str) -> Iterator[str]: """Read a large file line by line.""" with open(path) as f: for line in f: yield line.strip() # Usagefor line in read_large_file("huge.txt"): process(line)``` ## Data Classes and Named Tuples ### Data Classes ```pythonfrom dataclasses import dataclass, fieldfrom datetime import datetime @dataclassclass User: """User entity with automatic __init__, __repr__, and __eq__.""" id: str name: str email: str created_at: datetime = field(default_factory=datetime.now) is_active: bool = True # Usageuser = User( id="123", name="Alice", email="alice@example.com")``` ### Data Classes with Validation ```python@dataclassclass User: email: str age: int def __post_init__(self): # Validate email format if "@" not in self.email: raise ValueError(f"Invalid email: {self.email}") # Validate age range if self.age < 0 or self.age > 150: raise ValueError(f"Invalid age: {self.age}")``` ### Named Tuples ```pythonfrom typing import NamedTuple class Point(NamedTuple): """Immutable 2D point.""" x: float y: float def distance(self, other: 'Point') -> float: return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5 # Usagep1 = Point(0, 0)p2 = Point(3, 4)print(p1.distance(p2)) # 5.0``` ## Decorators ### Function Decorators ```pythonimport functoolsimport time def timer(func: Callable) -> Callable: """Decorator to time function execution.""" @functools.wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() result = func(*args, **kwargs) elapsed = time.perf_counter() - start print(f"{func.__name__} took {elapsed:.4f}s") return result return wrapper @timerdef slow_function(): time.sleep(1) # slow_function() prints: slow_function took 1.0012s``` ### Parameterized Decorators ```pythondef repeat(times: int): """Decorator to repeat a function multiple times.""" def decorator(func: Callable) -> Callable: @functools.wraps(func) def wrapper(*args, **kwargs): results = [] for _ in range(times): results.append(func(*args, **kwargs)) return results return wrapper return decorator @repeat(times=3)def greet(name: str) -> str: return f"Hello, {name}!" # greet("Alice") returns ["Hello, Alice!", "Hello, Alice!", "Hello, Alice!"]``` ### Class-Based Decorators ```pythonclass CountCalls: """Decorator that counts how many times a function is called.""" def __init__(self, func: Callable): functools.update_wrapper(self, func) self.func = func self.count = 0 def __call__(self, *args, **kwargs): self.count += 1 print(f"{self.func.__name__} has been called {self.count} times") return self.func(*args, **kwargs) @CountCallsdef process(): pass # Each call to process() prints the call count``` ## Concurrency Patterns ### Threading for I/O-Bound Tasks ```pythonimport concurrent.futuresimport threading def fetch_url(url: str) -> str: """Fetch a URL (I/O-bound operation).""" import urllib.request with urllib.request.urlopen(url) as response: return response.read().decode() def fetch_all_urls(urls: list[str]) -> dict[str, str]: """Fetch multiple URLs concurrently using threads.""" with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: future_to_url = {executor.submit(fetch_url, url): url for url in urls} results = {} for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] try: results[url] = future.result() except Exception as e: results[url] = f"Error: {e}" return results``` ### Multiprocessing for CPU-Bound Tasks ```pythondef process_data(data: list[int]) -> int: """CPU-intensive computation.""" return sum(x ** 2 for x in data) def process_all(datasets: list[list[int]]) -> list[int]: """Process multiple datasets using multiple processes.""" with concurrent.futures.ProcessPoolExecutor() as executor: results = list(executor.map(process_data, datasets)) return results``` ### Async/Await for Concurrent I/O ```pythonimport asyncio async def fetch_async(url: str) -> str: """Fetch a URL asynchronously.""" import aiohttp async with aiohttp.ClientSession() as session: async with session.get(url) as response: return await response.text() async def fetch_all(urls: list[str]) -> dict[str, str]: """Fetch multiple URLs concurrently.""" tasks = [fetch_async(url) for url in urls] results = await asyncio.gather(*tasks, return_exceptions=True) return dict(zip(urls, results))``` ## Package Organization ### Standard Project Layout ```myproject/├── src/│ └── mypackage/│ ├── __init__.py│ ├── main.py│ ├── api/│ │ ├── __init__.py│ │ └── routes.py│ ├── models/│ │ ├── __init__.py│ │ └── user.py│ └── utils/│ ├── __init__.py│ └── helpers.py├── tests/│ ├── __init__.py│ ├── conftest.py│ ├── test_api.py│ └── test_models.py├── pyproject.toml├── README.md└── .gitignore``` ### Import Conventions ```python# Good: Import order - stdlib, third-party, localimport osimport sysfrom pathlib import Path import requestsfrom fastapi import FastAPI from mypackage.models import Userfrom mypackage.utils import format_name # Good: Use isort for automatic import sorting# pip install isort``` ### __init__.py for Package Exports ```python# mypackage/__init__.py"""mypackage - A sample Python package.""" __version__ = "1.0.0" # Export main classes/functions at package levelfrom mypackage.models import User, Postfrom mypackage.utils import format_name __all__ = ["User", "Post", "format_name"]``` ## Memory and Performance ### Using __slots__ for Memory Efficiency ```python# Bad: Regular class uses __dict__ (more memory)class Point: def __init__(self, x: float, y: float): self.x = x self.y = y # Good: __slots__ reduces memory usageclass Point: __slots__ = ['x', 'y'] def __init__(self, x: float, y: float): self.x = x self.y = y``` ### Generator for Large Data ```python# Bad: Returns full list in memorydef read_lines(path: str) -> list[str]: with open(path) as f: return [line.strip() for line in f] # Good: Yields lines one at a timedef read_lines(path: str) -> Iterator[str]: with open(path) as f: for line in f: yield line.strip()``` ### Avoid String Concatenation in Loops ```python# Bad: O(n²) due to string immutabilityresult = ""for item in items: result += str(item) # Good: O(n) using joinresult = "".join(str(item) for item in items) # Good: Using StringIO for buildingfrom io import StringIO buffer = StringIO()for item in items: buffer.write(str(item))result = buffer.getvalue()``` ## Python Tooling Integration ### Essential Commands ```bash# Code formattingblack .isort . # Lintingruff check .pylint mypackage/ # Type checkingmypy . # Testingpytest --cov=mypackage --cov-report=html # Security scanningbandit -r . # Dependency managementpip-auditsafety check``` ### pyproject.toml Configuration ```toml[project]name = "mypackage"version = "1.0.0"requires-python = ">=3.9"dependencies = [ "requests>=2.31.0", "pydantic>=2.0.0",] [project.optional-dependencies]dev = [ "pytest>=7.4.0", "pytest-cov>=4.1.0", "black>=23.0.0", "ruff>=0.1.0", "mypy>=1.5.0",] [tool.black]line-length = 88target-version = ['py39'] [tool.ruff]line-length = 88select = ["E", "F", "I", "N", "W"] [tool.mypy]python_version = "3.9"warn_return_any = truewarn_unused_configs = truedisallow_untyped_defs = true [tool.pytest.ini_options]testpaths = ["tests"]addopts = "--cov=mypackage --cov-report=term-missing"``` ## Quick Reference: Python Idioms | Idiom | Description ||-------|-------------|| EAFP | Easier to Ask Forgiveness than Permission || Context managers | Use `with` for resource management || List comprehensions | For simple transformations || Generators | For lazy evaluation and large datasets || Type hints | Annotate function signatures || Dataclasses | For data containers with auto-generated methods || `__slots__` | For memory optimization || f-strings | For string formatting (Python 3.6+) || `pathlib.Path` | For path operations (Python 3.4+) || `enumerate` | For index-element pairs in loops | ## Anti-Patterns to Avoid ```python# Bad: Mutable default argumentsdef append_to(item, items=[]): items.append(item) return items # Good: Use None and create new listdef append_to(item, items=None): if items is None: items = [] items.append(item) return items # Bad: Checking type with type()if type(obj) == list: process(obj) # Good: Use isinstanceif isinstance(obj, list): process(obj) # Bad: Comparing to None with ==if value == None: process() # Good: Use isif value is None: process() # Bad: from module import *from os.path import * # Good: Explicit importsfrom os.path import join, exists # Bad: Bare excepttry: risky_operation()except: pass # Good: Specific exceptiontry: risky_operation()except SpecificError as e: logger.error(f"Operation failed: {e}")``` __Remember__: Python code should be readable, explicit, and follow the principle of least surprise. When in doubt, prioritize clarity over cleverness.Related skills
Agent Eval
Install Agent Eval skill for Claude Code from affaan-m/everything-claude-code.
Agent Harness Construction
Install Agent Harness Construction skill for Claude Code from affaan-m/everything-claude-code.
Agent Payment X402
Install Agent Payment X402 skill for Claude Code from affaan-m/everything-claude-code.