← Blog

Python Best Practices — Writing Clean and Maintainable Code

Oscar Dyremyhr·November 10, 2023·2 min read

Python is easy to write badly. That's not an insult — it's a feature that makes it accessible, but it's also why so many Python codebases become hard to maintain. Here are the practices I keep coming back to.

Type hints are not optional

If you're writing production Python in 2024 without type hints, you're making everyone's life harder, including future-you.

python
# Bad def process(data, threshold): return [x for x in data if x > threshold] # Better def process(data: list[float], threshold: float) -> list[float]: return [x for x in data if x > threshold]

Type hints are documentation that the runtime can check. Use them.

Prefer dataclasses over plain dicts

Passing dicts around is convenient until it isn't. When you need to know what keys a thing has, a dataclass makes that explicit.

python
from dataclasses import dataclass @dataclass class PipelineConfig: source_table: str target_table: str batch_size: int = 1000

Keep functions small and single-purpose

A function that does one thing is easy to test, easy to reason about, and easy to replace. A function that does five things is a liability.

The heuristic I use: if you need a comment to separate different "sections" of a function, split it.

Use pathlib, not os.path

python
# Old import os config_path = os.path.join(os.path.dirname(__file__), "config.yaml") # Better from pathlib import Path config_path = Path(__file__).parent / "config.yaml"

Handle errors explicitly

Don't catch broad Exception. Know what can fail and why.

python
# Bad try: result = fetch_data(url) except Exception: result = None # Better try: result = fetch_data(url) except requests.Timeout: logger.warning("Request timed out, retrying...") result = fetch_data(url, timeout=30) except requests.HTTPError as e: logger.error(f"HTTP error: {e.response.status_code}") raise

Test your assumptions

Write tests. Not for coverage metrics — for the assumptions you're making about the data, the APIs, the edge cases. When those assumptions break (and they will), you want to know immediately.


None of this is revolutionary. Clean code is mostly about discipline and consistency, not clever tricks. Pick a style, apply it consistently, and future-you will thank you.