Real-world Python best practices checklist that combines PEP 8, Pythonic principles, and software design standards. You can use this when writing, reviewing, or refactoring code.
- 4 spaces per indent level (no tabs).
- Max line length: 79 characters (or 88 if using black).
- Imports are grouped: stdlib → third-party → local, with blank lines.
- No wildcard imports (e.g.,
from module import \*). - Use snake_case for functions and variables.
- Use CamelCase for classes.
- Constants in
ALL_CAPS. - One blank line between methods inside a class.
- Two blank lines before top-level functions/classes.
- Use whitespace around operators and after commas.
- Avoid unnecessary parentheses or line breaks.
- Use truthy/falsy checks (
if my_list:notif len(my_list) > 0:). - Use list/set/dict comprehensions instead of loops when appropriate.
- Use
withstatements for file and resource handling. - Use
enumerate()instead of manual counters. - Use tuple unpacking where helpful (
a, b = b, a). - Prefer
inover manual iteration (if x in list:).
- Functions do one thing and are short (ideally < 50 lines).
- Clear function and parameter names.
- Type hints are used where useful:
def func(x: int) -> str. - Avoid global variables and mutable default arguments.
- Use
@staticmethod,@classmethod, or@propertywhen appropriate. - Break large classes into smaller, focused ones.
- Use
dataclassesfor simple data containers (Python 3.7+).
- Separate concerns into modules: models, views, utils, etc.
- Files are not too long or crowded.
- Avoid long functions, classes, or modules that do too much.
- Use docstrings for all public modules, functions, and classes.
- Avoid deep nesting (4+ levels).
- Use helper functions for repeated logic.
- Use
try/exceptto catch expected exceptions only. - Never use a bare except: – always catch specific errors.
- Don't swallow exceptions silently (pass in except is usually bad).
- Use
finallyor context managers to clean up resources. - Validate inputs and raise appropriate errors (e.g.,
ValueError).
- Functions/classes have a single responsibility.
- No copy-paste code; repeated logic is abstracted.
- Prefer composition over inheritance unless inheritance is natural.
- Code is open for extension, closed for modification.
- Abstractions are used to separate layers (e.g., DB access via interface).
- All core logic is covered by tests (use
pytestorunittest). - Avoid hard-to-test code (e.g., tightly coupled functions).
- Use
mypyorpyrightfor static type checking. - No print-based debugging left in production code.
- Add tests for edge cases and error conditions.
- Code is autoformatted with
blackorruffformat. flake8,pylint, orruffused to enforce lint rules.- Type checking passes (
mypy,pyright). - Tests can be run easily (
pytest, test runner setup). - Optional: Pre-commit hooks set up (pre-commit framework).
- Project includes a README with install & usage instructions.
- Complex functions/classes are documented with purpose and behavior.
- Public APIs include docstrings.
- Code comments are minimal but useful and up to date.
- Code favors readability over cleverness.
- Prefer simple solutions to complex ones.
- Avoid premature optimization.
- There’s one (preferably obvious) way to do it.
- Don’t reinvent the wheel – use Python’s standard library.