
Python Best Practices
- 1 installs
- 404 repo stars
- Updated August 5, 2026
- aiskillstore/marketplace
python-best-practices is a Claude Code skill providing type-first Python patterns using dataclasses, discriminated unions, NewType, and Protocol.
About
python-best-practices is a Claude Code skill providing type-first Python patterns for reading and writing Python code. It covers frozen dataclasses, discriminated unions with Literal, NewType for domain primitives, Enums, Protocol structural typing, TypedDict for external data, module structure, functional patterns, and explicit exception handling. A developer uses it to write well-typed, maintainable Python.
- Type-first Python development with dataclasses, discriminated unions, NewType, and Protocol
- Patterns to make illegal states unrepresentable via the type system
- Module structure, functional patterns, and explicit error-handling guidance
Python Best Practices by the numbers
- 1 all-time installs (skills.sh)
- Ranked #240 of 290 Python skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
python-best-practices capabilities & compatibility
Free; a pattern/reference skill with no external service
- Capabilities
- refactoring · code quality · typing
- Use cases
- refactoring · api development
- Pricing
- Free
What python-best-practices says it does
Provides Python patterns for type-first development with dataclasses, discriminated unions, NewType, and Protocol.
Use Python's type system to prevent invalid states at type-check time.
npx skills add https://github.com/aiskillstore/marketplace --skill python-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 404 |
| Last updated | August 5, 2026 |
| Repository | aiskillstore/marketplace ↗ |
What it does
Write type-first Python using dataclasses, discriminated unions, NewType, Protocol, and explicit error handling.
Who is it for?
Writing well-typed, maintainable Python with types defined before implementation
Skip if: Non-Python languages or runtime-heavy tasks unrelated to code structure
When should I use this skill?
Reading or writing Python files
What you get
Type-safe Python where illegal states are unrepresentable and failures are explicit.
- type-first Python modules
- typed data models
By the numbers
- recommends splitting modules over ~300 lines
- covers 6 typing constructs (dataclass, Literal union, NewType, Enum, Protocol, TypedDict)
Files
Python Best Practices
Type-First Development
Types define the contract before implementation. Follow this workflow:
1. Define data models - dataclasses, Pydantic models, or TypedDict first 2. Define function signatures - parameter and return type hints 3. Implement to satisfy types - let the type checker guide completeness 4. Validate at boundaries - runtime checks where data enters the system
Make Illegal States Unrepresentable
Use Python's type system to prevent invalid states at type-check time.
Dataclasses for structured data:
from dataclasses import dataclass
from datetime import datetime
@dataclass(frozen=True)
class User:
id: str
email: str
name: str
created_at: datetime
@dataclass(frozen=True)
class CreateUser:
email: str
name: str
# Frozen dataclasses are immutable - no accidental mutationDiscriminated unions with Literal:
from dataclasses import dataclass
from typing import Literal
@dataclass
class Idle:
status: Literal["idle"] = "idle"
@dataclass
class Loading:
status: Literal["loading"] = "loading"
@dataclass
class Success:
status: Literal["success"] = "success"
data: str
@dataclass
class Failure:
status: Literal["error"] = "error"
error: Exception
RequestState = Idle | Loading | Success | Failure
def handle_state(state: RequestState) -> None:
match state:
case Idle():
pass
case Loading():
show_spinner()
case Success(data=data):
render(data)
case Failure(error=err):
show_error(err)NewType for domain primitives:
from typing import NewType
UserId = NewType("UserId", str)
OrderId = NewType("OrderId", str)
def get_user(user_id: UserId) -> User:
# Type checker prevents passing OrderId here
...
def create_user_id(raw: str) -> UserId:
return UserId(raw)Enums for constrained values:
from enum import Enum, auto
class Role(Enum):
ADMIN = auto()
USER = auto()
GUEST = auto()
def check_permission(role: Role) -> bool:
match role:
case Role.ADMIN:
return True
case Role.USER:
return limited_check()
case Role.GUEST:
return False
# Type checker warns if case is missingProtocol for structural typing:
from typing import Protocol
class Readable(Protocol):
def read(self, n: int = -1) -> bytes: ...
def process_input(source: Readable) -> bytes:
# Accepts any object with a read() method
return source.read()TypedDict for external data shapes:
from typing import TypedDict, Required, NotRequired
class UserResponse(TypedDict):
id: Required[str]
email: Required[str]
name: Required[str]
avatar_url: NotRequired[str]
def parse_user(data: dict) -> UserResponse:
# Runtime validation needed - TypedDict is structural
return UserResponse(
id=data["id"],
email=data["email"],
name=data["name"],
)Module Structure
Prefer smaller, focused files: one class or closely related set of functions per module. Split when a file handles multiple concerns or exceeds ~300 lines. Use __init__.py to expose public API; keep implementation details in private modules (_internal.py). Colocate tests in tests/ mirroring the source structure.
Functional Patterns
- Use list/dict/set comprehensions and generator expressions over explicit loops.
- Prefer
@dataclass(frozen=True)for immutable data; avoid mutable default arguments. - Use
functools.partialfor partial application; compose small functions over large classes. - Avoid class-level mutable state; prefer pure functions that take inputs and return outputs.
Instructions
- Raise descriptive exceptions for unsupported cases; every code path returns a value or raises. This makes failures debuggable and prevents silent corruption.
- Propagate exceptions with context using
from err; catching requires re-raising or returning a meaningful result. Swallowed exceptions hide root causes. - Handle edge cases explicitly: empty inputs,
None, boundary values. Includeelseclauses in conditionals where appropriate. - Use context managers for I/O; prefer
pathliband explicit encodings. Resource leaks cause production issues. - Add or adjust unit tests when touching logic; prefer minimal repros that isolate the failure.
Examples
Explicit failure for unimplemented logic:
def build_widget(widget_type: str) -> Widget:
raise NotImplementedError(f"build_widget not implemented for type: {widget_type}")Propagate with context to preserve the original traceback:
try:
data = json.loads(raw)
except json.JSONDecodeError as err:
raise ValueError(f"invalid JSON payload: {err}") from errExhaustive match with explicit default:
def process_status(status: str) -> str:
match status:
case "active":
return "processing"
case "inactive":
return "skipped"
case _:
raise ValueError(f"unhandled status: {status}")Debug-level tracing with namespaced logger:
import logging
logger = logging.getLogger("myapp.widgets")
def create_widget(name: str) -> Widget:
logger.debug("creating widget: %s", name)
widget = Widget(name=name)
logger.debug("created widget id=%s", widget.id)
return widgetConfiguration
- Load config from environment variables at startup; validate required values before use. Missing config should fail immediately.
- Define a config dataclass or Pydantic model as single source of truth; avoid
os.getenvscattered throughout code. - Use sensible defaults for development; require explicit values for production secrets.
Examples
Typed config with dataclass:
import os
from dataclasses import dataclass
@dataclass(frozen=True)
class Config:
port: int = 3000
database_url: str = ""
api_key: str = ""
env: str = "development"
@classmethod
def from_env(cls) -> "Config":
database_url = os.environ.get("DATABASE_URL", "")
if not database_url:
raise ValueError("DATABASE_URL is required")
return cls(
port=int(os.environ.get("PORT", "3000")),
database_url=database_url,
api_key=os.environ["API_KEY"], # required, will raise if missing
env=os.environ.get("ENV", "development"),
)
config = Config.from_env()Optional: ty
For fast type checking, consider ty from Astral (creators of ruff and uv). Written in Rust, it's significantly faster than mypy or pyright.
Installation and usage:
# Run directly with uvx (no install needed)
uvx ty check
# Check specific files
uvx ty check src/main.py
# Install permanently
uv tool install tyKey features:
- Automatic virtual environment detection (via
VIRTUAL_ENVor.venv) - Project discovery from
pyproject.toml - Fast incremental checking
- Compatible with standard Python type hints
Configuration in `pyproject.toml`:
[tool.ty]
python-version = "3.12"When to use ty vs alternatives:
ty- fastest, good for CI and large codebases (early stage, rapidly evolving)pyright- most complete type inference, VS Code integrationmypy- mature, extensive plugin ecosystem
{
"schema_version": "2.0",
"meta": {
"generated_at": "2026-01-16T12:50:05.681Z",
"slug": "0xbigboss-python-best-practices",
"source_url": "https://github.com/0xBigBoss/claude-code/tree/main/.claude/skills/python-best-practices",
"source_ref": "main",
"model": "claude",
"analysis_version": "3.0.0",
"source_type": "community",
"content_hash": "c0019f9fea234b80b38ad6a516fa051f270a0fdafc1ddcdf266777e520f5e88c",
"tree_hash": "df21e803ced7866acdf2046f9aba6cd488e1f13e2ec5615218d21f9d95eca38a"
},
"skill": {
"name": "python-best-practices",
"description": "Provides Python patterns for type-first development with dataclasses, discriminated unions, NewType, and Protocol. Must use when reading or writing Python files.",
"summary": "Provides Python patterns for type-first development with dataclasses, discriminated unions, NewType,...",
"icon": "🐍",
"version": "1.0.0",
"author": "0xBigBoss",
"license": "MIT",
"category": "coding",
"tags": [
"python",
"type-safety",
"patterns",
"best-practices",
"dataclasses"
],
"supported_tools": [
"claude",
"codex",
"claude-code"
],
"risk_factors": [
"network",
"filesystem",
"external_commands",
"env_access"
]
},
"security_audit": {
"risk_level": "safe",
"is_blocked": false,
"safe_to_publish": true,
"summary": "This is a pure documentation skill containing only markdown guidance with code examples. The static analyzer incorrectly flagged example code patterns in documentation as security issues. All reported findings are FALSE POSITIVES because the skill contains no executable code, no file system access, no network calls, and no external command execution. The flagged patterns (backticks, environment variables, API keys in examples) are educational documentation content only.",
"risk_factor_evidence": [
{
"factor": "network",
"evidence": [
{
"file": "skill-report.json",
"line_start": 6,
"line_end": 6
},
{
"file": "SKILL.md",
"line_start": 241,
"line_end": 241
}
]
},
{
"factor": "filesystem",
"evidence": [
{
"file": "skill-report.json",
"line_start": 6,
"line_end": 6
}
]
},
{
"factor": "external_commands",
"evidence": [
{
"file": "SKILL.md",
"line_start": 22,
"line_end": 39
},
{
"file": "SKILL.md",
"line_start": 39,
"line_end": 42
},
{
"file": "SKILL.md",
"line_start": 42,
"line_end": 76
},
{
"file": "SKILL.md",
"line_start": 76,
"line_end": 79
},
{
"file": "SKILL.md",
"line_start": 79,
"line_end": 91
},
{
"file": "SKILL.md",
"line_start": 91,
"line_end": 94
},
{
"file": "SKILL.md",
"line_start": 94,
"line_end": 111
},
{
"file": "SKILL.md",
"line_start": 111,
"line_end": 114
},
{
"file": "SKILL.md",
"line_start": 114,
"line_end": 123
},
{
"file": "SKILL.md",
"line_start": 123,
"line_end": 126
},
{
"file": "SKILL.md",
"line_start": 126,
"line_end": 142
},
{
"file": "SKILL.md",
"line_start": 142,
"line_end": 146
},
{
"file": "SKILL.md",
"line_start": 146,
"line_end": 146
},
{
"file": "SKILL.md",
"line_start": 146,
"line_end": 146
},
{
"file": "SKILL.md",
"line_start": 146,
"line_end": 151
},
{
"file": "SKILL.md",
"line_start": 151,
"line_end": 152
},
{
"file": "SKILL.md",
"line_start": 152,
"line_end": 158
},
{
"file": "SKILL.md",
"line_start": 158,
"line_end": 159
},
{
"file": "SKILL.md",
"line_start": 159,
"line_end": 159
},
{
"file": "SKILL.md",
"line_start": 159,
"line_end": 160
},
{
"file": "SKILL.md",
"line_start": 160,
"line_end": 166
},
{
"file": "SKILL.md",
"line_start": 166,
"line_end": 169
},
{
"file": "SKILL.md",
"line_start": 169,
"line_end": 172
},
{
"file": "SKILL.md",
"line_start": 172,
"line_end": 177
},
{
"file": "SKILL.md",
"line_start": 177,
"line_end": 180
},
{
"file": "SKILL.md",
"line_start": 180,
"line_end": 189
},
{
"file": "SKILL.md",
"line_start": 189,
"line_end": 192
},
{
"file": "SKILL.md",
"line_start": 192,
"line_end": 202
},
{
"file": "SKILL.md",
"line_start": 202,
"line_end": 207
},
{
"file": "SKILL.md",
"line_start": 207,
"line_end": 213
},
{
"file": "SKILL.md",
"line_start": 213,
"line_end": 237
},
{
"file": "SKILL.md",
"line_start": 237,
"line_end": 244
},
{
"file": "SKILL.md",
"line_start": 244,
"line_end": 253
},
{
"file": "SKILL.md",
"line_start": 253,
"line_end": 256
},
{
"file": "SKILL.md",
"line_start": 256,
"line_end": 256
},
{
"file": "SKILL.md",
"line_start": 256,
"line_end": 257
},
{
"file": "SKILL.md",
"line_start": 257,
"line_end": 261
},
{
"file": "SKILL.md",
"line_start": 261,
"line_end": 262
},
{
"file": "SKILL.md",
"line_start": 262,
"line_end": 265
},
{
"file": "SKILL.md",
"line_start": 265,
"line_end": 268
},
{
"file": "SKILL.md",
"line_start": 268,
"line_end": 269
},
{
"file": "SKILL.md",
"line_start": 269,
"line_end": 270
}
]
},
{
"factor": "env_access",
"evidence": [
{
"file": "SKILL.md",
"line_start": 226,
"line_end": 226
},
{
"file": "SKILL.md",
"line_start": 230,
"line_end": 230
},
{
"file": "SKILL.md",
"line_start": 232,
"line_end": 232
},
{
"file": "SKILL.md",
"line_start": 233,
"line_end": 233
},
{
"file": "SKILL.md",
"line_start": 220,
"line_end": 220
},
{
"file": "SKILL.md",
"line_start": 226,
"line_end": 226
},
{
"file": "SKILL.md",
"line_start": 226,
"line_end": 226
},
{
"file": "SKILL.md",
"line_start": 227,
"line_end": 227
},
{
"file": "SKILL.md",
"line_start": 228,
"line_end": 228
},
{
"file": "SKILL.md",
"line_start": 231,
"line_end": 231
},
{
"file": "SKILL.md",
"line_start": 231,
"line_end": 231
},
{
"file": "SKILL.md",
"line_start": 221,
"line_end": 221
},
{
"file": "SKILL.md",
"line_start": 232,
"line_end": 232
},
{
"file": "SKILL.md",
"line_start": 232,
"line_end": 232
}
]
}
],
"critical_findings": [],
"high_findings": [],
"medium_findings": [],
"low_findings": [],
"dangerous_patterns": [],
"files_scanned": 2,
"total_lines": 447,
"audit_model": "claude",
"audited_at": "2026-01-16T12:50:05.681Z"
},
"content": {
"user_title": "Apply Python Type-First Patterns",
"value_statement": "Writing Python without type definitions leads to runtime errors and hard-to-maintain code. This skill provides battle-tested patterns for type-first development using dataclasses, discriminated unions, Protocols, and other modern Python features to make illegal states unrepresentable.",
"seo_keywords": [
"Python best practices",
"type-first development",
"Claude Code Python",
"dataclasses patterns",
"Python type hints",
"Protocol typing",
"NewType Python",
"discriminated unions",
"Claude Python coding",
"Python type safety"
],
"actual_capabilities": [
"Provides dataclass patterns for immutable data structures",
"Guides discriminated union implementation with Literal types",
"Documents NewType usage for domain primitive wrappers",
"Explains Protocol for structural typing",
"Covers TypedDict for external data shape validation",
"Shares functional patterns and error handling best practices"
],
"limitations": [
"Does not execute or validate Python code",
"Does not access or modify user project files",
"Does not install dependencies or run type checkers",
"Does not provide real-time code completion or linting"
],
"use_cases": [
{
"target_user": "Python developers",
"title": "Design type-safe data models",
"description": "Learn to use dataclasses, NewType, and discriminated unions to encode domain constraints at the type level."
},
{
"target_user": "Code reviewers",
"title": "Review Python type patterns",
"description": "Apply consistent typing patterns across codebases using Protocols, TypedDict, and exhaustively matched unions."
},
{
"target_user": "AI agents",
"title": "Generate idiomatic Python",
"description": "Produce Python code that follows modern type-first patterns when working with Claude, Codex, or Claude Code."
}
],
"prompt_templates": [
{
"title": "Create data model",
"scenario": "Define a type-safe data structure",
"prompt": "Create a frozen dataclass with proper type hints for a user profile including required fields and optional avatar. Use the python-best-practices patterns."
},
{
"title": "Handle state machine",
"scenario": "Model state transitions",
"prompt": "Model a request state machine with idle, loading, success, and failure states using discriminated unions and pattern matching. Apply python-best-practices patterns."
},
{
"title": "Add type safety",
"scenario": "Wrap primitive types",
"prompt": "Create NewType wrappers for UserId and OrderId to prevent mixing them up. Show how to validate input and create the wrapped types."
},
{
"title": "Define interface",
"scenario": "Create protocol for duck typing",
"prompt": "Define a Protocol for a file-like object with read method, then show how to use it as a type hint for functions that accept any read-compatible object."
}
],
"output_examples": [
{
"input": "Create a frozen dataclass for a product with required name and price, optional description",
"output": [
"Use @dataclass(frozen=True) for immutability",
"Mark required fields without defaults first",
"Add optional fields with default values after required fields",
"The frozen=True flag prevents accidental mutation",
"Example output shows proper field ordering and type hints"
]
},
{
"input": "Show how to handle state transitions with discriminated unions",
"output": [
"Define separate classes for each state (Idle, Loading, Success, Failure)",
"Use Literal types to discriminate states",
"Apply pattern matching with match/case for exhaustive handling",
"Raise errors for unhandled cases",
"Keep state logic isolated and testable"
]
},
{
"input": "Create a typed configuration loader from environment variables",
"output": [
"Define a frozen dataclass with typed fields",
"Use os.environ.get with defaults for optional values",
"Use os.environ[] for required secrets",
"Validate configuration at load time",
"Fail fast if required values are missing"
]
}
],
"best_practices": [
"Define types before implementation; let the type checker guide completeness",
"Use frozen dataclasses and immutable patterns to prevent accidental state mutation",
"Validate data at system boundaries with runtime checks alongside type hints"
],
"anti_patterns": [
"Using mutable default arguments in function signatures",
"Skipping type hints for 'obvious' return types",
"Catching exceptions without re-raising or adding context"
],
"faq": [
{
"question": "What Python versions support these patterns?",
"answer": "Pattern matching requires Python 3.10+. Dataclasses and typing features work on 3.7+. Use pyright or mypy for older projects."
},
{
"question": "How does this compare to Pydantic?",
"answer": "Dataclasses provide compile-time types. Pydantic adds runtime validation. Use both together for maximum safety."
},
{
"question": "Can I use this with FastAPI or Django?",
"answer": "Yes. These patterns complement web frameworks. Define models with dataclasses, use them in route handlers."
},
{
"question": "Does this skill access my code?",
"answer": "No. This is a knowledge-only skill. It provides guidance but cannot read, write, or execute your code."
},
{
"question": "What type checker should I use?",
"answer": "pyright offers best inference and VS Code integration. mypy has more plugins. ty is fastest for large codebases."
},
{
"question": "When should I use TypedDict vs dataclass?",
"answer": "Use dataclasses for internal Python objects. Use TypedDict when matching external JSON or dict structures."
}
]
},
"file_structure": [
{
"name": "SKILL.md",
"type": "file",
"path": "SKILL.md",
"lines": 271
}
]
}
Related skills
FAQ
What is the type-first workflow?
Define data models first, then function signatures, then implement to satisfy the types, and validate at boundaries.
How does it prevent invalid states?
By using frozen dataclasses, discriminated unions, NewType, Enums, and Protocol so illegal states are unrepresentable at type-check time.