Documentation

Good documentation can turn a project into something that people can use, understand, and maintain. It lowers the barrier for new contributors, clarifies how and why public APIs behave the way they do, and makes it easier to track changes as your project evolves. Without good documentation, even well-written code can quickly become a game of guesswork, scaring away users and contributors.

Here are some best practices that you can apply while documenting your Python code:

  • Document the public API of your project. Add meaningful docstrings to public packages, modules, functions, methods, and classes. Focus on what each object does, its arguments and return values, and when it can fail or raise exceptions. This practice makes your project easier to use and safer to change.
  • Write a clear README file with usage examples. Add a README file that explains what the project does, how to install it, how to run simple examples, and where to find more documentation. Small, concrete code samples are often more helpful and to the point than long descriptions.
  • Separate different types of documentation. Use docstrings to describe public APIs and inline comments sparingly to explain non-obvious implementation details. Keep tutorials, how-to guides, and broader explanations in external documentation.
  • Keep documentation close to the code and generate it automatically. Store documentation alongside the code and use tools like Sphinx or MkDocs (with appropriate plugins) to build HTML documentation from docstrings and markup files. This reduces duplication and helps keep your documentation in sync with the code.
  • Update documentation as part of your development cycle. Treat documentation as part of each feature. When you implement changes, update the relevant docstrings and external documentation at the same time. This helps prevent documentation from drifting out of date.

To see the impact of documentation on usability, consider the following hypothetical function:

🔴 Avoid this:

Python
def send(email, retries=3):
    # Send email
    # Implementation...

This function provides no clear information on what it does or how to use it. It has a vague name, the comment is incomplete, and the user must guess how to call it, what happens in case of failure, and whether the function returns anything useful.

Favor this:

Python
def send_welcome_email(address: str, *, retries: int = 3) -> None:
    """Send a welcome email to a new user.

    Args:
        address (str): Destination email address.
        retries (int): Number of times to retry on transient errors.

    Raises:
        ValueError: If the address is empty or invalid.
        EmailDeliveryError: If sending fails after all retries.
    """
    # Implementation...

In this version, the function name clearly states its purpose. The docstring explains what the function does, how to call it, and what the arguments mean. It also states what callers can expect in terms of errors.

Documentation tools like Sphinx, or MkDocs with suitable plugins, can extract this docstring and include it in a generated API reference automatically.

Tutorial

Documenting Python Code: A Complete Guide

A complete guide to documenting Python code. Whether you're documenting a small script or a large project, whether you're a beginner or seasoned Pythonista, this guide will cover everything you need to know.

intermediate best-practices

For additional information on related topics, take a look at the following resources:


By Leodanis Pozo Ramos • Updated Dec. 23, 2025 • Reviewed by Brenda Weleschuk and Bartosz Zaczyński