How to Document Python Code Using Docstrings

Originally posted on makeuseof.

Good code includes comments to help understand it, and docstrings can play a major role in that.

Without proper documentation, it can be difficult to understand, maintain, and debug your code. In Python, you can use docstrings to provide concise descriptions and examples of how the code works.

What Are Docstrings?

Docstrings are strings you can add to your Python code to explain what it does and how to use it. The piece of code can be a Python function, a module, or a class.

Docstrings look a lot like standard Python comments, but they have some differences. Python comments provide additional information to developers about the code’s inner workings, such as implementation details or caveats to keep in mind when extending the code.

On the other hand, docstrings mostly provide information to users of the code who may not necessarily need to know its implementation details but need to understand what it does and how to use it.

How to Write Docstrings

You typically include docstrings at the beginning of the block of code you want to document. You must enclose them in triple quotes (“””). You can write one-line docstrings or multi-line docstrings.

One-line docstrings are suitable for simple code that doesn’t require a lot of documentation.

Below is an example of a function called multiply. The docstring explains the multiply function takes two numbers, multiples them, and returns the result.

def multiply(a, b):
    """Multiplies two numbers and returns the result"""
    return a * b

Use multi-line docstrings for more complex code that needs detailed documentation.

Consider the following Car class:

class Car:
    """
    A class representing a car object.

    Attributes:
        mileage (float): The current mileage of the car.

    Methods:
        drive(miles): Drives the car for the specified number of miles.
    """

    def __init__(self, mileage):
        self.mileage = mileage

    def drive(self, miles):
        """
        Drives the car for the specified number of miles.

        Args:
            miles (float): The number of miles to drive.

        Returns:
            None
        """
        self.mileage += miles

The docstring for the above class describes what the class represents, its attributes, and its methods. Meanwhile, the docstrings for the drive method provide information about what the method does, the arguments it expects, and what it returns.

This makes it easier for anyone working with this class to understand how to use it. The other benefits of using docstrings include:

  • Code maintainability: By providing a clear description of how the code works, docstrings help developers modify and update the code without introducing errors.
  • Easier collaboration: When several developers are collaborating on the same code base—for instance, with the Visual Studio live share tool—docstrings allow developers to document the code consistently so that everyone on the team can understand it.
  • Improved code readability: Docstrings provide a high-level summary of what code does which allows anyone reading the code to quickly understand its purpose without going through the entire code block.

Docstring Formats

A good docstring should describe what a piece of code does, the arguments it expects, and implementation details if necessary. It should especially include any edge cases anyone using the code should be aware of.

A basic docstring format has the following sections:

  • Summary line: A one-line summary of what the code does.
  • Arguments: Information about the arguments the function expects including their data types.
  • Return value: Information about the return value of the function including its data type.
  • Raises (optional): Information about any exceptions the function may raise.

This is just a basic format as there are other formats you can choose to base your docstrings. The most popular ones are Epytext, reStructuredText (also known as reST), NumPy, and Google docstrings. Each of these formats has its own syntax as shown in the following examples:

Epytext

A docstring that follows the Epytext format:

def multiply(a, b):
    """
    Multiply two numbers together.

 @param a: The first number to multiply.
 @type a: int
 @param b: The second number to multiply.
 @type b: int
 @return: The product of the two numbers.
 @rtype: int
    """
    return a * b

reStructuredText (reST)

A docstring that follows the reST format:

def multiply(a, b):
    """
    Multiply two numbers together.

    :param a: The first number to multiply.
    :type a: int
    :param b: The second number to multiply.
    :type b: int
    :return: The product of the two numbers.
    :rtype: int
    """
    return a * b

NumPy

A docstring that follows the NumPy format:

def multiply(a, b):
    """
    Multiply two numbers together.

    Parameters
    ----------
    a : int
        The first number to multiply.
    b : int
        The second number to multiply.

    Returns
    -------
    int
        The product of the two numbers.
    """
    return a * b

Google

A docstring that follows the Google format:

def multiply(a, b):
    """
    Multiply two numbers together.

    Args:
        a (int): The first number to multiply.
        b (int): The second number to multiply.

    Returns:
        int: The product of the two numbers.
    """
    return a * b

Although all four docstring formats provide useful documentation for the multiply function, the NumPy and Google formats are easier to read than the Epytext and reST formats.

How to Include Tests in the Docstrings

You can include testing examples in your docstrings using the doctest module. The doctest module searches the docstring for text that looks like interactive Python sessions and then executes them to verify that they work as they should.

To use doctests, include the sample inputs and expected outputs in the docstring. Below is an example of how you would do that:

def multiply(a, b):
    """
    Multiply two numbers together.

    Parameters
    ----------
    a : int
        The first number to multiply.
    b : int
        The second number to multiply.

    Returns
    -------
    int
        The product of the two numbers.
 
    Examples
    --------
    >>> multiply(2, 3)
    6
    >>> multiply(0, 10)
    0
    >>> multiply(-1, 5)
    -5
    """
    return a * b

The Examples section contains three function calls with different arguments and specifies the expected output for each. When you run the doctest module as shown below, it will execute the examples and compare the actual output to the expected output.

python -m doctest multiply.py

If there are any differences, the doctest module reports them as failures. Using doctests with docstrings like this helps you verify that the code is working as expected. Note that doctests are not a replacement for more comprehensive unit tests and integration tests for your Python code.

How to Generate Documentation From Docstrings

You’ve learned the basics of using docstrings to document your Python code and the importance of high-quality documentation. To take it up a notch, you may want to generate documentation for your modules and functions from their respective docstrings.

One of the most popular documentation generators you can use is Sphinx. It supports reST docstring format by default but you can configure it to work with the Google or NumPy format.

Source: makeuseof