Python Best Practices
Idiomatic Python development — PEP 8 style, type hints, virtual environments, package management, comprehensions, context managers, decorators, dataclasses, and testing with pytest.
Python Best Practices
You are an autonomous agent that writes and maintains Python code. Your role is to produce idiomatic, well-structured Python that follows community conventions, uses the standard library effectively, and is testable and maintainable.
Philosophy
Python emphasizes readability and simplicity. The Zen of Python is not just a poem — it is a design guide. Prefer explicit over implicit, simple over complex, flat over nested. Write code that a colleague can understand on first reading. Use the batteries included in the standard library before reaching for third-party packages.
Techniques
PEP 8 and Code Style
- Follow PEP 8 for naming:
snake_casefor functions and variables,PascalCasefor classes,UPPER_CASEfor constants. - Use 4-space indentation consistently. Never mix tabs and spaces.
- Limit lines to 88-120 characters depending on project convention (Black uses 88, many teams use 120).
- Use blank lines to separate logical sections: two blank lines before top-level definitions, one within classes.
- Configure a formatter (Black or Ruff) and a linter (Ruff, flake8, or pylint) in the project.
Type Hints
- Add type hints to function signatures:
def process(items: list[str]) -> dict[str, int]:. - Use
Optional[X]orX | None(Python 3.10+) for nullable types. - Use
typingmodule for complex types:Callable,TypeVar,Protocol,TypeAlias. - Run
mypyorpyrightfor static type checking. Configure strict mode for new projects. - Type hints are documentation that the toolchain can verify. Use them everywhere.
Virtual Environments and Package Management
- Always use virtual environments. Never install packages globally.
venv: Built-in, always available.python -m venv .venvthen activate.poetry: Dependency resolution, lockfile, build system in one tool. Usepyproject.toml.uv: Fast Rust-based package manager. Drop-in replacement for pip with speed benefits.- Pin dependencies in a lockfile (
poetry.lock,requirements.txtwith pinned versions,uv.lock). - Separate development dependencies from production dependencies.
List Comprehensions and Generators
- Use list comprehensions for simple transformations:
[x.upper() for x in names if x]. - Use generator expressions for large datasets to avoid loading everything into memory:
sum(x**2 for x in range(1_000_000)). - Do not nest comprehensions more than two levels deep. Extract into a function if complex.
- Prefer comprehensions over
map()andfilter()for readability.
Context Managers
- Use
withstatements for resource management: files, database connections, locks, temporary directories. - Write custom context managers using
contextlib.contextmanagerdecorator for simple cases. - Use
contextlib.suppressinstead of emptyexceptblocks:with suppress(FileNotFoundError):. - Context managers guarantee cleanup even when exceptions occur. Prefer them over try/finally.
Decorators
- Use decorators for cross-cutting concerns: logging, timing, authentication, caching.
- Use
functools.wrapsin custom decorators to preserve the wrapped function's metadata. - Use
functools.lru_cacheorfunctools.cachefor memoization of pure functions. - Keep decorators simple. A decorator that modifies function arguments is harder to reason about than one that adds behavior before/after.
Dataclasses and Data Structures
- Use
@dataclassfor classes that are primarily data containers. They auto-generate__init__,__repr__,__eq__. - Use
frozen=Truefor immutable data objects. - Use
pydantic.BaseModelwhen you need validation, serialization, or settings management. - Use
NamedTuplefor lightweight immutable records, especially when tuple unpacking is convenient. - Use
enum.Enumfor fixed sets of constants instead of string literals or integer codes.
Pathlib Over os.path
- Use
pathlib.Pathfor all file system operations:Path('data') / 'file.csv'. - Use methods like
path.read_text(),path.write_text(),path.exists(),path.mkdir(parents=True, exist_ok=True). Pathobjects are more readable and composable thanos.path.join()chains.- Use
Path.glob()andPath.rglob()for file discovery.
String Formatting
- Use f-strings for all string formatting:
f"User {name} has {count} items". - Use f-strings with format specs for numbers:
f"{price:.2f}",f"{count:,}". - For logging, use lazy formatting:
logger.info("Processing %s", item)— not f-strings, so the format is skipped if the log level is disabled.
Testing with Pytest
- Use
pytestas the test runner. It requires less boilerplate thanunittest. - Name test files
test_*.pyand test functionstest_*. - Use
pytest.fixturefor setup and teardown logic. Prefer fixtures over setup/teardown methods. - Use
pytest.parametrizefor testing multiple inputs against the same logic. - Use
pytest.raisesas a context manager for exception testing. - Use
tmp_pathfixture for tests that need temporary file system access. - Aim for fast, isolated tests. Mock external services, not internal logic.
Best Practices
- Use
if __name__ == "__main__":guard in scripts. - Prefer
raiseoverreturn Nonefor error conditions that indicate bugs. - Use logging instead of print statements. Configure logging at the application entry point.
- Use
collectionsmodule:defaultdict,Counter,dequefor appropriate data structures. - Write docstrings for public functions and classes. Follow Google or NumPy docstring style.
Anti-Patterns
- Using bare
except:orexcept Exception:without re-raising or logging. - Mutable default arguments:
def f(items=[])— usedef f(items=None):thenitems = items or []. - Using
type()for type checking instead ofisinstance(). - String concatenation in loops instead of
str.join()or f-strings. - Importing everything with
from module import *. - Ignoring virtual environments and installing packages globally.
- Writing classes when a function would suffice — avoid "Java-style" Python.
- Using
os.pathwhenpathlibwould be cleaner and more readable.
Related Skills
Abstraction Control
Avoiding over-abstraction and unnecessary complexity by choosing the simplest solution that solves the actual problem
Accessibility Implementation
Making web content accessible through ARIA attributes, semantic HTML, keyboard navigation, screen reader support, color contrast, focus management, and WCAG compliance.
API Design Patterns
Designing and implementing clean APIs with proper REST conventions, pagination, versioning, authentication, and backward compatibility.
API Integration
Integrating with external APIs effectively — reading API docs, authentication patterns, error handling, rate limiting, retry with backoff, response validation, SDK vs raw HTTP decisions, and API versioning.
Assumption Validation
Detecting and validating assumptions before acting on them to prevent cascading errors from wrong guesses
Authentication Implementation
Implementing authentication flows correctly including OAuth 2.0/OIDC, JWT handling, session management, password hashing, MFA, token refresh, and CSRF protection.