✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Documenting Python Code

Documenting Python Code involves using comments, docstrings, and tools to explain code purpose, functionality, and usage for better readability and collaboration.

Documenting Python code is fundamentally about communicating intent, contracts, usage, assumptions, externally meaningful behavior, and non-obvious implementation reasoning. This communication occurs through comments, docstrings, interface documentation, examples, runtime help, and documentation-generation mechanisms, each serving distinct but complementary roles in helping users and maintainers understand and work effectively with Python code.


Foundations of Documenting Python Code

Documentation is information that helps readers understand how and why Python code should be used or maintained. It is distinct from the executable behavior itself, which is defined by the code’s syntax and semantics. Documentation supplements code by clarifying intent, constraints, and usage that are not immediately obvious from the code alone.

Useful documentation emphasizes intent, public behavior, assumptions, invariants, limitations, side effects, and rationale. It avoids mechanically restating syntax or operations already clear from the code. Instead, it provides insights into why code exists and how it should be used or modified safely.

Different documentation forms answer different questions:

  • Comments explain local reasoning, assumptions, or subtle details within the code.
  • Docstrings describe interfaces by capturing purpose, parameters, return values, and usage contracts.
  • Type annotations specify data types but do not fully describe semantics.
  • Examples demonstrate typical interface usage concretely.
  • External prose documentation provides conceptual overviews, tutorials, and rationale.
  • Generated reference material compiles structured interface information for browsing or lookup.
Documentation FormAudienceLocationPrimary ResponsibilityRelationship to Executable Code
CommentsCode maintainersInside source codeExplain non-obvious details, rationaleInline, ignored by interpreter
DocstringsUsers and maintainersFirst statement in modules, classes, functionsDocument interface contracts and usageAccessible at runtime via __doc__
Interface DocumentationInterface usersModules, packages, classes, functionsDescribe public API purpose and constraintsDerived from docstrings and source
ExamplesInterface users, learnersDocstrings, external docsShow representative usage and expected resultsIllustrative, runnable or illustrative
Runtime HelpInteractive usersREPL, consolesProvide on-demand access to docstringsUses docstrings and introspection
Generated DocumentationDevelopers, usersHTML, PDF, websitesPresent structured reference and navigationBased on source docstrings and metadata

A clear conceptual illustration:

Python Source Comments & Docstrings Developer Reading Understand code & intent Runtime Help Interactive doc access Examples Demonstrate usage Generated Docs Reference material

Documentation maintenance is an integral part of code maintenance. Outdated documentation can be worse than no documentation because readers may treat it as authoritative and be misled. Keeping documentation synchronized with code changes ensures it remains trustworthy and effective.


Python Code Comments

Python comments are source text beginning with # outside string literals. They communicate information only to human readers and do not become part of runtime expression evaluation.

Block comments are groups of comment lines associated with a following logical section of code. They describe purpose, reasoning, assumptions, or constraints rather than mechanically translating each statement into English.

Example:

# Increment the counter for each valid user
counter += 1  # This comment merely repeats the code

# The counter tracks the number of active users who passed validation,
# including those with exceptions for special roles.
# It must never exceed the maximum allowed concurrent sessions.
counter += 1  # Non-obvious invariant explained here

Inline comments are brief annotations following code. Use them sparingly when a localized non-obvious fact cannot be expressed more clearly by naming or code structure.

Concise examples:

Useful inline comment:

result = compute_discount(price)  # price in USD, excludes taxes

Unnecessary inline comment:

x = x + 1  # add one to x

Over-commented example rewritten:

# Over-commented
# Calculate the sum of x and y
sum = x + y  # add x and y

# Improved: descriptive naming and structure
def add(x, y):
    return x + y
sum = add(x, y)

Comments recording rationale, compatibility constraints, deliberate deviations, units, external assumptions, or subtle algorithmic properties remain valuable even when implementations change.

Maintenance markers like TODO or FIXME should be actionable and include sufficient context to identify the unresolved issue rather than vague reminders.

Avoid commented-out obsolete code. Prefer removal or use version-control history for reference.

Poorly commented function:

def calc(a, b):
    # check if a is positive
    if a > 0:
        # do division
        return a / b  # returns result
    else:
        # return zero if not positive
        return 0

Revised:

def divide_if_positive(a, b):
    # Returns a / b if a > 0; otherwise returns 0.
    # Assumes b != 0.
    if a > 0:
        return a / b
    return 0

Python Docstrings

A docstring is a string literal recognized as documentation when it appears as the first statement in a module, class, function, or method body. Unlike arbitrary string literals elsewhere, recognized docstrings are accessible via the documented object's __doc__ attribute.

Example with docstrings:

"""Module-level docstring describing module purpose."""

class Example:
    """This class represents an example abstraction."""

    def method(self):
        """Perform an action and return True on success."""
        return True

def func(x):
    """Compute the square of x."""
    return x * x

print(__doc__)                    # Module docstring
print(Example.__doc__)            # Class docstring
print(Example.method.__doc__)     # Method docstring
print(func.__doc__)               # Function docstring

One-line docstrings provide concise summaries suitable for simple interfaces and should describe purpose or behavior rather than repeat names or signatures.

Multi-line docstrings start with a summary, followed by a blank line, then detailed explanation covering behavior, parameters, return values, exceptions, side effects, invariants, or usage notes—only when these materially help users.

Well-documented function example:

def calculate_area(radius):
    """
    Calculate the area of a circle given its radius.

    Parameters:
        radius (float): Radius of the circle, must be non-negative.

    Returns:
        float: Area of the circle.

    Raises:
        ValueError: If radius is negative.

    Notes:
        Uses π approximated by math.pi.
    """
    import math
    if radius < 0:
        raise ValueError("Radius cannot be negative")
    return math.pi * radius ** 2

Public docstrings document behavior rather than implementation internals so refactoring internals does not unnecessarily invalidate the interface contract.

Only document exceptions callers need to understand—do not list every incidental internal exception.

Document mutation, persistent state changes, external effects, or resource ownership when relevant to safe usage.

Docstring formatting conventions vary; semantic completeness and consistency matter more than mixing markup styles arbitrarily.

Raw docstrings (prefixing with r) prevent backslash escapes from being interpreted but do not change conceptual content.


Python Interface Documentation

Interface documentation focuses on what users of modules, packages, classes, functions, methods, and scripts need to use them correctly without depending on private implementation details.

Module and Package Documentation in Python

Document modules by explaining their purpose, principal public capabilities, important module-level assumptions, representative usage, and relationships among public interfaces.

Example module:

"""
math_utils.py

Provides mathematical utilities for geometric calculations.
"""

PI = 3.141592653589793

class Circle:
    """Represents a circle with a given radius."""

    def __init__(self, radius):
        """Initialize circle with radius."""
        self.radius = radius

    def area(self):
        """Return the area of the circle."""
        return PI * self.radius ** 2

def square(x):
    """Return the square of x."""
    return x * x

Package-level documentation communicates the package's conceptual purpose, major public entry points, initialization behavior if relevant, and how users should approach the public interface, without cataloging every internal module.

Class Documentation in Python

Document the abstraction represented by a class, construction expectations, important invariants, significant public attributes, and behavioral responsibilities.

Example class with documentation:

class Rectangle:
    """
    Represents a rectangle defined by width and height.

    Invariants:
        width > 0
        height > 0

    Public attributes:
        width (float): Width of the rectangle.
        height (float): Height of the rectangle.
    """

    def __init__(self, width, height):
        """Initialize a rectangle with width and height."""
        self.width = width
        self.height = height

    def area(self):
        """Return the area of the rectangle."""
        return self.width * self.height

Document public attributes when names and annotations alone do not fully convey their meaning, units, mutability, or lifecycle.

Function and Method Documentation in Python

Document operation purpose, parameter semantics, return meaning, exceptions, side effects, preconditions, postconditions, and usage examples according to interface complexity.

Documentation ConcernWhen Useful
PurposeAlways, to explain what the function does
ParametersWhen semantics, constraints, or units matter
Return ValueWhen meaning or special cases affect use
ExceptionsWhen callers need to handle specific failures
Side EffectsWhen mutations or external effects occur
PreconditionsWhen callers must satisfy conditions
State ChangesWhen persistent or global state is affected
ExamplesTo illustrate typical or boundary usage

Parameter documentation adds semantic information such as meaning, accepted forms, units, or constraints beyond names and type annotations.

Document return values through their semantic meaning and special cases like None or sentinels with distinct caller interpretation.

Contrasting docstrings:

def multiply(x, y):
    """Multiply x and y."""
    return x * y

def multiply(x, y):
    """
    Multiply two numbers.

    Parameters:
        x (int or float): First factor.
        y (int or float): Second factor.

    Returns:
        int or float: Product of x and y.
    """
    return x * y

Script Documentation in Python

Document directly executable Python programs with purpose, invocation expectations, input/output behavior, side effects, exit behavior, configuration assumptions, and representative command usage. Avoid turning comments into full manuals.

Example script docstring:

"""
process_data.py

Process input data files to generate summarized reports.

Usage:
    python process_data.py input.csv output.txt

Arguments:
    input.csv   CSV file containing raw data
    output.txt  File to write summary results

Behavior:
    Reads input, filters invalid rows, computes aggregates,
    and writes textual report to output.

Exit codes:
    0 on success, non-zero on failure.
"""

Interface documentation describes externally meaningful behavior, while implementation comments explain local reasoning that maintainers need.


Examples in Python Documentation

Documentation examples concretely demonstrate intended interface use, complementing abstract descriptions by showing representative inputs, operations, and observable results.

Select examples that first demonstrate common successful use, then important boundary, configuration, or failure behavior only if they materially improve understanding.

Example interface with usage examples:

def factorial(n):
    """
    Compute factorial of n (n!).

    Examples:
        >>> factorial(5)
        120
        >>> factorial(0)
        1
    """
    if n == 0:
        return 1
    return n * factorial(n - 1)

Examples serve as executable-looking contracts using valid contemporary Python syntax, realistic values, and outputs consistent with documented behavior.

Interactive-style examples using >>> prompts suit human reading and may be verified by doctest tools but are distinct from comprehensive testing.

Example with interactive-style examples:

def greet(name):
    """
    Return a greeting message.

    Examples:
        >>> greet('Alice')
        'Hello, Alice!'
    """
    return f"Hello, {name}!"

Examples involving randomness, time, unordered output, environment-specific paths, concurrency, or external state require deliberate stabilization or abstraction so documentation does not imply one accidental result is universally guaranteed.

Avoid unnecessary setup, huge datasets, incidental framework details, and unexplained magic values that obscure the interface concept.

Keep examples synchronized with interface evolution; obsolete names, stale outputs, removed parameters, or changed semantics are documentation defects, not harmless drift.


Python Online Help and Documentation Generation

Python online help provides runtime access to documentation metadata for modules, classes, functions, methods, and other objects, principally deriving useful descriptions from names, signatures, docstrings, and object structure.

The built-in help() function offers an interactive interface displaying documentation about Python objects. Its usefulness depends on the quality of docstrings and introspection information exposed.

Representative interactive uses of help():

>>> import math
>>> help(math)
Help on module math:

NAME
    math

DESCRIPTION
    This module provides access to the mathematical functions
    defined by the C standard.

FUNCTIONS
    ...
>>> help(math.sqrt)
Help on built-in function sqrt in module math:

sqrt(x, /)
    Return the square root of x.

Access to raw docstrings via __doc__ differs from normalized retrieval through inspect.getdoc, which cleans indentation and formatting for display.

Example comparing __doc__ and inspect.getdoc:

import inspect

def example():
    """
    This is a multi-line docstring.
    It has indentation and extra spaces.
    """
    pass

print("Raw __doc__:")
print(example.__doc__)
print("\nNormalized inspect.getdoc:")
print(inspect.getdoc(example))

The standard pydoc module locates Python objects and renders documentation derived from runtime interfaces and docstrings.

Representative pydoc commands:

$ python -m pydoc math
$ python -m pydoc math.sqrt
$ python -m pydoc -w math  # Write HTML documentation for math module

Programmatic example using pydoc:

import pydoc

print(pydoc.render_doc(str))

Documentation generation transforms structured interface information—signatures, names, docstrings, and optional markup—into reference-oriented output. Generated presentation is distinct from the quality of the underlying documentation.

Generating reference documentation from maintained source interfaces reduces duplication and keeps signatures near implementation. Conceptual guides, tutorials, rationale, and architecture explanations often require separately authored prose.

Limitations of automatic generation include propagation of stale docstrings, exposure of unintended interfaces, poor organization, missing conceptual context, and mechanically complete but unhelpful reference material.

Tool / AttributeInput ObjectNormalizationPresentation PurposeProgrammatic UseRepresentative Audience
__doc__Object's raw docstringNoneRaw docstring textDirect access to stored stringDevelopers inspecting source
inspect.getdocObjectTrim and clean layoutCleaned docstring for displayDisplay-friendly docstringDevelopers, runtime help
help()ObjectUses inspect.getdocInteractive help in REPLInteractive useInteractive users
pydocObject or name stringUses inspect.getdocFormatted reference documentationProgrammatic or CLIDevelopers, users, documentation consumers

Solved Python Documentation Exercise

Initial version (weak names, redundant comments, missing public docstrings, undocumented side effects, no usage example):

# This module does some math operations

def f1(x, y):
    # add x and y
    return x + y  # returns sum

def f2(x):
    # multiply x by 2
    return x * 2

class C:
    # class for math ops
    def m1(self, val):
        # subtract 1
        return val - 1

Documented version:

"""
math_ops.py

Provides simple mathematical operations for demonstration purposes.

This module includes addition, doubling, and decrement operations
with clear contracts and usage examples.
"""

def add(x, y):
    """
    Return the sum of x and y.

    Parameters:
        x (number): First addend.
        y (number): Second addend.

    Returns:
        number: Sum of x and y.

    Examples:
        >>> add(2, 3)
        5
    """
    return x + y

def double(x):
    """
    Return twice the value of x.

    Parameters:
        x (number): Input value.

    Returns:
        number: Two times x.

    Examples:
        >>> double(4)
        8
    """
    return x * 2

class Calculator:
    """
    Calculator for simple arithmetic operations.

    Methods:
        decrement(val): Return val minus one.
    """

    def decrement(self, val):
        """
        Return val decreased by one.

        Parameters:
            val (number): Value to decrement.

        Returns:
            number: val minus one.

        Notes:
            This method does not mutate any state.
        """
        return val - 1

Explanation of improvements:

  • Removed redundant comments that restated obvious operations.
  • Added a module docstring describing purpose and contents.
  • Renamed functions and class for clarity and to express intent.
  • Added docstrings to functions and methods to specify parameters, return values, and examples.
  • Preserved rationale by noting that decrement does not mutate state.
  • Included usage examples to demonstrate typical calls.
  • Structured documentation supports runtime help and generated documentation.

Verification code for documentation retrieval:

import math_ops
import inspect
import pydoc

print("Module __doc__:")
print(math_ops.__doc__)

print("\nFunction add __doc__:")
print(math_ops.add.__doc__)

print("\nNormalized docstring via inspect.getdoc for add:")
print(inspect.getdoc(math_ops.add))

print("\nHelp for Calculator class:")
help(math_ops.Calculator)

print("\nPydoc for double function:")
print(pydoc.render_doc(math_ops.double))

Reviewing Python documentation involves checking for:

  • Missing purpose statements.
  • Duplicated or trivial syntax restatement.
  • Unexplained parameters or special return cases.
  • Stale or misleading examples.
  • Undocumented side effects or state changes.
  • Misleading comments or implementation leakage.
  • Inconsistent terminology or naming.
  • Documentation that no longer matches executable behavior.

Documentation density should match conceptual and interface complexity. Simple code requires minimal prose; subtle public behavior, state transitions, constraints, or external effects justify more detailed documentation.

Terminology consistency is important: stable names should be used for identical concepts to avoid reader confusion.

Public documentation must describe supported behavior and not promise incidental implementation details that may legitimately change without breaking the interface contract.