← 输入框|python.land|刷新

Python Docstring: Documenting Your Code

A python docstring allows you to document your code more formally. We’ll first look at what a docstring is exactly. Next, we’ll create our own docstrings, from a single line to a fully documented function. I’ll also show you how to read docstrings, and how to test the examples inside them.

What is a Python docstring?

Let’s start by defining what a docstring is. This is taken straight from PEP 257, which describes the conventions for docstrings:

Docstring
A docstring is a string that occurs as the first statement in a module, function, class, or method definition. Such a docstring becomes the __doc__ special attribute of that object.

There’s a clear distinction between Python comments and docstrings. A comment is ignored completely by the Python interpreter, while a docstring is an actual string that the interpreter sees. Because we don’t assign the string, it doesn’t change what the code does. So the effect of a docstring, in short, is the same as a comment: it’s a piece of text that documents your code.

However, there’s still an essential difference between comments and docstrings, because Python can actually find and show the docstring when asked for, since it gets assigned to the __doc__ special attribute. Your IDE uses it too: hover over a function call in VS Code or PyCharm, and you’ll see its docstring. That makes docstrings the way to formally document your code, as you’ll soon learn.

How to create Python docstrings

As defined above, we can simply insert a string as the first statement of any module, function, class, or method and it becomes the docstring. Here’s an example of how to document a Python class and its functions using docstrings:

class MyDocumentedClass:
    """This class is well documented but doesn't do anything special."""

    def do_nothing(self):
        """This method doesn't do anything but feel free to call it anyway."""
        pass

As you can see, I created these strings with triple double quotes. That’s the convention from PEP 257, and for a reason: they are more recognizable as a docstring, and it’s easier to expand them to multi-line strings later on (if needed).

A one-line docstring should be a short phrase that ends in a period. PEP 257 recommends writing it as a command, like “Return the average…”, rather than as a description, like “Returns the average…”.

Multi-line docstrings

Often, one line isn’t enough. PEP 257 describes how to write a longer docstring:

  1. Start with a one-line summary, on the same line as the opening quotes.
  2. Add a blank line.
  3. Then add the details: what the function expects, what it returns, and anything else a user needs to know.
  4. Put the closing quotes on a line of their own.

The summary line matters most. Tools that list many functions at once, like help() on a module and the autocomplete in your IDE, often show only that first line.

Documenting parameters and return values

PEP 257 doesn’t prescribe how to describe parameters and return values, so a few styles have become popular. The most readable one, in my opinion, is the Google style. Here’s a small module, stats.py, with a module docstring at the top and a fully documented function:

"""Simple statistics helpers.

This module contains a few small functions to summarize lists of numbers.
"""


def average(numbers: list[float]) -> float:
    """Return the average of a list of numbers.

    Args:
        numbers: A non-empty list of numbers.

    Returns:
        The arithmetic mean of the numbers.

    Raises:
        ZeroDivisionError: If the list is empty.

    Examples:
        >>> average([1, 2, 3, 4])
        2.5
        >>> average([10])
        10.0
    """
    return sum(numbers) / len(numbers)

Each section has a fixed name, like Args: or Returns:, followed by an indented description. Because the function has type hints, I don’t repeat the types in the docstring. Your IDE and other tools read them from the hints.

You’ll also run into two other styles. The NumPy style is common in scientific projects, like NumPy and pandas. It uses underlined section headers:

def average(numbers):
    """Return the average of a list of numbers.

    Parameters
    ----------
    numbers : list of float
        A non-empty list of numbers.

    Returns
    -------
    float
        The arithmetic mean of the numbers.
    """
    return sum(numbers) / len(numbers)

The reStructuredText (reST) style comes from Sphinx, the documentation tool that’s also used for Python’s own documentation. It uses field markers:

def average(numbers):
    """Return the average of a list of numbers.

    :param numbers: A non-empty list of numbers.
    :type numbers: list[float]
    :returns: The arithmetic mean of the numbers.
    :rtype: float
    :raises ZeroDivisionError: If the list is empty.
    """
    return sum(numbers) / len(numbers)

Which one should you pick? If your project already uses one, stick with it. Otherwise, I’d go with the Google style. All three are understood by documentation generators like Sphinx and mkdocstrings, which turn your docstrings into a documentation website.

How to read docstrings

The docstring is internally assigned to the __doc__ special attribute. Usually, you don’t access it that way, though. Instead, we call help(MyDocumentedClass) in a Python REPL to see the result of these docstrings:

Help on class MyDocumentedClass in module __main__:

class MyDocumentedClass(builtins.object)
 |  This class is well documented but doesn't do anything special.
 |
 |  Methods defined here:
 |
 |  do_nothing(self)
 |      This method doesn't do anything but feel free to call it anyway.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables
 |
 |  __weakref__
 |      list of weak references to the object

The part at the bottom, about __dict__ and __weakref__, is something every class gets automatically. You can ignore it for now.

You can use help on any object in Python. I encourage you to try this. E.g., enter help(print) to get the docstring from the print function, or help(str) to view the string class with all its useful methods. You can also ask for the documentation of methods within a class, e.g. with help(str.title) you can learn what the title() method on a string object does.

Test your examples with doctest

Did you notice the Examples: section in the average() docstring? Those lines look like a REPL session, and that’s on purpose. Python’s built-in doctest module can find them, run them, and check that the output matches. Run it on the file from the command line:

$ python3 -m doctest stats.py

If all examples pass, doctest prints nothing at all. Add -v to see what it’s doing. Now, let’s say I made a mistake and wrote 2.0 as the expected result of the first example. Doctest catches it:

**********************************************************************
File "/home/erik/stats.py", line 20, in stats.average
Failed example:
    average([1, 2, 3, 4])
Expected:
    2.0
Got:
    2.5
**********************************************************************
1 item had failures:
   1 of   2 in stats.average
***Test Failed*** 1 failure.

This keeps the examples in your documentation honest: when you change the code, outdated examples fail. Doctest isn’t a replacement for real unit tests, but it’s a great fit for small, clear examples.

Keep learning

Related articles

Leave a Comment