โ† Back to Coding Agents & IDEs
Coding Agents & IDEs by @adarshdigievo

python

Python coding guidelines and best practices

0
Source Code

Python Coding Guidelines

Code Style (PEP 8)

  • 4 spaces for indentation (never tabs)
  • Max line length: 88 chars (Black default) or 79 (strict PEP 8)
  • Two blank lines before top-level definitions, one within classes
  • Imports: stdlib โ†’ third-party โ†’ local, alphabetized within groups
  • Snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants

Before Committing

# Syntax check (always)
python -m py_compile *.py

# Run tests if present
python -m pytest tests/ -v 2>/dev/null || python -m unittest discover -v 2>/dev/null || echo "No tests found"

# Format check (if available)
ruff check . --fix 2>/dev/null || python -m black --check . 2>/dev/null

Python Version

  • Minimum: Python 3.10+ (3.9 EOL Oct 2025)
  • Target: Python 3.11-3.13 for new projects
  • Never use Python 2 syntax or patterns
  • Use modern features: match statements, walrus operator, type hints

Dependency Management

Check for uv first, fall back to pip:

# Prefer uv if available
if command -v uv &>/dev/null; then
    uv pip install <package>
    uv pip compile requirements.in -o requirements.txt
else
    pip install <package>
fi

For new projects with uv: uv init or uv venv && source .venv/bin/activate

Pythonic Patterns

# โœ… List/dict comprehensions over loops
squares = [x**2 for x in range(10)]
lookup = {item.id: item for item in items}

# โœ… Context managers for resources
with open("file.txt") as f:
    data = f.read()

# โœ… Unpacking
first, *rest = items
a, b = b, a  # swap

# โœ… EAFP over LBYL
try:
    value = d[key]
except KeyError:
    value = default

# โœ… f-strings for formatting
msg = f"Hello {name}, you have {count} items"

# โœ… Type hints
def process(items: list[str]) -> dict[str, int]:
    ...

# โœ… dataclasses/attrs for data containers
from dataclasses import dataclass

@dataclass
class User:
    name: str
    email: str
    active: bool = True

# โœ… pathlib over os.path
from pathlib import Path
config = Path.home() / ".config" / "app.json"

# โœ… enumerate, zip, itertools
for i, item in enumerate(items):
    ...
for a, b in zip(list1, list2, strict=True):
    ...

Anti-patterns to Avoid

# โŒ Mutable default arguments
def bad(items=[]):  # Bug: shared across calls
    ...
def good(items=None):
    items = items or []

# โŒ Bare except
try:
    ...
except:  # Catches SystemExit, KeyboardInterrupt
    ...
except Exception:  # Better
    ...

# โŒ Global state
# โŒ from module import * 
# โŒ String concatenation in loops (use join)
# โŒ == None (use `is None`)
# โŒ len(x) == 0 (use `not x`)

Testing

  • Use pytest (preferred) or unittest
  • Name test files test_*.py, test functions test_*
  • Aim for focused unit tests, mock external dependencies
  • Run before every commit: python -m pytest -v

Docstrings

def fetch_user(user_id: int, include_deleted: bool = False) -> User | None:
    """Fetch a user by ID from the database.
    
    Args:
        user_id: The unique user identifier.
        include_deleted: If True, include soft-deleted users.
    
    Returns:
        User object if found, None otherwise.
    
    Raises:
        DatabaseError: If connection fails.
    """

Quick Checklist

  • Syntax valid (py_compile)
  • Tests pass (pytest)
  • Type hints on public functions
  • No hardcoded secrets
  • f-strings, not .format() or %
  • pathlib for file paths
  • Context managers for I/O
  • No mutable default args