Python Best Practices

Autonomous Agents Intermediate autonomous-agent-skills universal
0 Upvotes
55 Views
0 Downloads
873 Words

Description

Writes idiomatic, well-documented Python code that follows PEP 8, uses type hints, manages virtual environments and packaging, and is ready for testing.

When to Use

give me Python best practices | show me how to organize a Python project | how to write type hints and tests in Python | refactor this script to idiomatic Python

Use Cases

Convert a script to idiomatic Python with tests. | Set up a new Python project with venv and pyproject.toml. | Add type hints to public APIs for clarity. | Configure Black and Ruff for formatting and linting. | Refactor code to use dataclasses and context managers.

About this skill

Python Best Practices is a free SKILL.md agent skill in the Autonomous Agents category for Claude Code, OpenAI Codex and other SKILL.md-compatible agents. The file is about 961 words long and is rated intermediate difficulty. To use it, copy or download the file and save it as python-best-practices/SKILL.md inside your agent's skills folder (for Claude Code, .claude/skills/).

New to skills? Read the SKILL.md format and manifest spec or the complete guide to AI agent skills. Browse more Autonomous Agents agent skills (121) or the full SKILL.md skill library.

SKILL.md Content

---
name: python-best-practices
description: "Writes idiomatic, well-documented Python code that follows PEP 8, uses type hints, manages virtual environments and packaging, and is ready for testing."
metadata:
  tags: "autonomous-agents, python, python-best-practices, pep8, type-hints, virtual-environments, testing"
  source: "https://skilldb.dev/skills/autonomous-agent-skills/python-best-practices"
  pack: "autonomous-agent-skills"
  category: "Autonomous Agents"
---

# Python Best Practices

## When to use this skill
Use when the user says things like:
- "give me Python best practices"
- "show me how to organize a Python project"
- "how to write type hints and tests in Python"
- "refactor this script to idiomatic Python"


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_case` for functions and variables, `PascalCase` for classes, `UPPER_CASE` for 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]` or `X | None` (Python 3.10+) for nullable types.
- Use `typing` module for complex types: `Callable`, `TypeVar`, `Protocol`, `TypeAlias`.
- Run `mypy` or `pyright` for 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 .venv` then activate.
- `poetry`: Dependency resolution, lockfile, build system in one tool. Use `pyproject.toml`.
- `uv`: Fast Rust-based package manager. Drop-in replacement for pip with speed benefits.
- Pin dependencies in a lockfile (`poetry.lock`, `requirements.txt` with 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()` and `filter()` for readability.

### Context Managers
- Use `with` statements for resource management: files, database connections, locks, temporary directories.
- Write custom context managers using `contextlib.contextmanager` decorator for simple cases.
- Use `contextlib.suppress` instead of empty `except` blocks: `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.wraps` in custom decorators to preserve the wrapped function's metadata.
- Use `functools.lru_cache` or `functools.cache` for 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 `@dataclass` for classes that are primarily data containers. They auto-generate `__init__`, `__repr__`, `__eq__`.
- Use `frozen=True` for immutable data objects.
- Use `pydantic.BaseModel` when you need validation, serialization, or settings management.
- Use `NamedTuple` for lightweight immutable records, especially when tuple unpacking is convenient.
- Use `enum.Enum` for fixed sets of constants instead of string literals or integer codes.

### Pathlib Over os.path
- Use `pathlib.Path` for 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)`.
- `Path` objects are more readable and composable than `os.path.join()` chains.
- Use `Path.glob()` and `Path.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 `pytest` as the test runner. It requires less boilerplate than `unittest`.
- Name test files `test_*.py` and test functions `test_*`.
- Use `pytest.fixture` for setup and teardown logic. Prefer fixtures over setup/teardown methods.
- Use `pytest.parametrize` for testing multiple inputs against the same logic.
- Use `pytest.raises` as a context manager for exception testing.
- Use `tmp_path` fixture 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 `raise` over `return None` for error conditions that indicate bugs.
- Use logging instead of print statements. Configure logging at the application entry point.
- Use `collections` module: `defaultdict`, `Counter`, `deque` for appropriate data structures.
- Write docstrings for public functions and classes. Follow Google or NumPy docstring style.

## Anti-Patterns
- Using bare `except:` or `except Exception:` without re-raising or logging.
- Mutable default arguments: `def f(items=[])` — use `def f(items=None):` then `items = items or []`.
- Using `type()` for type checking instead of `isinstance()`.
- 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.path` when `pathlib` would be cleaner and more readable.