Python Fundamentals Best Practices
Core habits that keep Python code readable, correct, and maintainable before you reach for frameworks or data tools. Treat this as a onboarding checklist for every new module or repo.
Search across all documentation pages
Core habits that keep Python code readable, correct, and maintainable before you reach for frameworks or data tools. Treat this as a onboarding checklist for every new module or repo.
pyproject.toml and a lockfile (uv.lock). Reproducible CI and clones.requires-python in pyproject.toml.ruff check and ruff format on every PR. Fast style and lint feedback.snake_case functions, PascalCase classes, UPPER constants.% formatting and format() for new code. Clearer and faster.pathlib.Path instead of os.path string juggling. Cross-platform safe joins.def f(x=[])). Use None and assign inside.Decimal for money, not binary float. Avoid 0.1 + 0.2 surprises in billing.encoding="utf-8" on all text file I/O. Prevent platform-default bugs.copy.deepcopy when independence matters. Shallow copies share inner lists.isinstance for type checks, not type(x) is Cls on subclasses. Polymorphism-friendly.append loops when transforming sequences. Readable and often faster.match/case for structural branching on dicts and dataclasses. Cleaner than deep if chains.* in public APIs. Prevents ambiguous call sites.if __name__ == "__main__":. Importable modules without side effects.python -m package.module. Correct relative imports and __package__.from myapp.utils import x). Clearer than relative in large trees.types modules. Fail fast at design time when possible.json.py, types.py). Breaks imports mysteriously.src/ layout for installable packages. Prevents accidental imports from repo root.No - configure ruff and focus on readability. Automate formatting debates away.
Module-level constants and cached read-only config are fine. Mutable globals complicate tests - prefer injection.
Optional for throwaway scripts. Add them when the script grows or becomes a package.
match for structure (dict keys, typed events). if for simple scalar conditions.
This cookbook pins uv 0.6+ as the default fast path. Poetry remains valid for teams already standardized on it.
Start with new modules at strict optional flags; widen gradually. Pydantic models at HTTP boundaries first.
Better for map/filter transforms. Use a for loop when side effects or complex branching dominate.
print is fine for CLI UX. Services should use logging with structured fields - see errors-logging section.
Explicit comparisons (is None, len(x) == 0) when falsy-but-valid values like 0 matter.
Isolated environments with locked dependencies - everything else fails without reproducible installs.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 16, 2026