This skill should be used when the user asks to "write Python code", "create a Python module", "set up a Python project", "review Python code", "refactor Python", "add type hints", "fix Python style", or when generating any Python source code. Provides modern Python 3.12+ best practices covering syntax, type hints, error handling, project structure, and idiomatic patterns. Does not cover any specific library or framework.
Pure Python best practices for writing clean, idiomatic, and type-safe code. All guidance targets Python 3.12+ and covers only the standard language and stdlib — no third-party libraries or frameworks.
| Element | Convention | Example |
|---|---|---|
| Module | snake_case | data_loader.py |
| Package | lowercase | utils/, core/ |
| Class | PascalCase | UserAccount |
| Function/Method | snake_case | get_user_by_id() |
| Variable | snake_case | retry_count |
| Constant |
UPPER_SNAKEMAX_RETRIES |
| Type alias | PascalCase | type UserId = int |
| Private | _leading | _internal_cache |
| Name-mangled | __double | __secret (rarely needed) |
| Dunder | __name__ | Reserved for Python protocols |
Prefix boolean variables and functions with is_, has_, can_, or should_.
| Legacy | Modern (3.12+) |
|---|---|
Union[X, Y] | X | Y |
Optional[X] | X | None |
TypeAlias = ... | type Alias = ... |
List[str], Dict[str, int] | list[str], dict[str, int] |
Tuple[int, ...] | tuple[int, ...] |
if/elif/elif chains on a value | match/case |
os.path.join() | pathlib.Path |
"{}".format(x) | f"{x}" |
Use match/case for value dispatch, destructuring, and type narrowing — not as a simple switch replacement. See references/modern-syntax.md for detailed patterns.
match command:
case {"action": "move", "direction": str(d)}:
handle_move(d)
case {"action": "quit"}:
handle_quit()
case _:
handle_unknown(command)
type statement (3.12+)type Vector = list[float]
type Result[T] = T | Error
type Handler[**P] = Callable[P, Awaitable[None]]
Apply type hints to all function signatures, class attributes, and module-level variables. Omit return type only for __init__.
def calculate_total(items: list[float], *, tax_rate: float = 0.0) -> float:
...
Key rules:
list[str], dict[str, int], tuple[int, ...], set[str]X | None instead of Optional[X]type statement for aliases, not bare assignmentProtocol over ABC when only structural typing is needed@override decorator (3.12+) when overriding base class methodsSelf for methods returning the instance typeFor comprehensive typing patterns including generics, Protocol, TypeGuard, TypeVar, and ParamSpec, consult references/type-hints.md.
Define domain errors as a hierarchy inheriting from a project-level base:
class AppError(Exception):
"""Base for all application errors."""
class ValidationError(AppError):
"""Invalid input data."""
class NotFoundError(AppError):
"""Requested resource does not exist."""
except:.raise NewError(...) from original.ExceptionGroup and except* for concurrent error aggregation.with statement) for resource cleanup — avoid manual try/finally.