Skip to the content.

Documentation and Docstrings

Back to Python

You should never write code that is impossible to read. Python makes it easy to NOT do that, but sometimes, stuff gets complex. Documentation is there to make your code more readable and understandable.

Table of Contents

The Zen of Python

If you open a Python repl and import this, you will be presented with text that describes some of the design philosophy behind Python.

Some key takeaways:

Docstrings

A docstring is a string that describes a module, function, class, or method. It is surrounded by triple quotation marks (either single or double).

Since everything is an object in Python, the docstring is directly associated with the object as the built-in member object.doc, which means it’s viewable with help() as well as built-in function documentation viewers.

Examples:

"""This is a one-liner docstring."""

"""
Here's another docstring except
spread over multiple lines.
"""

Docstrings are seperated into sections. Each section describes something specific such as function parameters or return types.

Example of a Docstring with Sections:

def sum_all(elem: list[int]) -> int:
    """
    Sums all the elements of the list.

    Parameters
    ----------
    elem : list[int]
        The list of elements to sum.

    Returns
    -------
    sum : int
        The sum of the elements of elem.
    """
    total = 0
    for e in elem:
        total += e
    return total

Docstrings follow the following general syntax:

"""
Description

Heading Name
------------
Heading Body

Heading Name 2
--------------
Heading Body 2
"""

General Description Section

Each docstring should have a general description section. This section is pretty simple.

It can be a short or long description of object, but keep it simple and understandable. It may also include extended summary after it, also without a heading.

Note that a single one-liner description would have the triple quotes all on the same line.

Example:

"""This is a one-liner docstring with only a description."""


"""
Here is a highly descriptive extended summary that requires more
than one line and is followed by the next section heading.

Example Section
---------------
"""

Docstrings for Functions

We’re gonna use the numpydoc documentation style (with some additional modern typing standards).

Sections in Order:

"""
<Description>
[Parameters]
[Returns]
[Yields]
[Receives]
[Other Parameters]
[Raises]
[Warns]
[Warnings]
[See Also]
[Notes]
[References]
[Examples]
"""

Parameters Section

Syntax:

"""
Parameters
----------
param1_name : param1_type
    param1_description
param2_name : param2_type
    param2_description
similar_param3_name, similar_param4_name : common_param_type
    common_param_description
"""

A much more complicated example:

"""
Parameters
----------
val : int
    A good description of val
vals : list[int]
    A good description of what’s in vals
some_quadruplet : tuple[bool, bool, bool, bool]
    A good description of what each value of the tuple means
(val1, val2, name) : tuple[int, int, str]
    A good description of what each value of the tuple means
some_choice : {"Choice A", "Choice B", "Choice C"}
    A good description of each possibility of some choice
my_bool : bool, default=False
    A good description of my_bool
my_float : float, optional (or float, default=None)
    A good description of my_float and what happens when it’s None
*args : tuple[MyType]
    Description of variable-length positional arguments parameter, may list possibilities or example
**kwargs : dict[str, MyType]
    Description of variable-length keyword arguments parameter, may list possibilities

"""

Returns Section

Syntax:

"""
Returns
-------
return_name : return_type
    return_description
"""

Examples:

# typed return: int
"""
Returns
-------
summation : int
    sum of all values
"""

# typed return: Union[int, float, bool, None]
"""
Returns
-------
int | float | bool | None
    summation : int | float | bool
        The sum of the values or logical or in the case of bools
    None (or alternatively “none : None”)
        result if any of the values were 0
"""

A much more complicated example:

# typed return: Dict[str, Tuple[int, int, List[str]]]
"""
Returns
-------
locations : dict[str, tuple[int, int, list[str]]]
    the locations of the buildings on the map
    name : str
        the identifying name of the building
    bldg_info : tuple[int, int list[str]]
        row : int
            the row value of the building on the map
        col : int
            the column value of the building on the map
        managers : list[str]
            the names of the building managers
            name : str
                name of a building manager in the form of "FIRST MIDDLE LAST"
"""

Yields Section

Syntax:

"""
Yields
------
yield_type
    a good description of the yield and how it relates to the next value
"""

# or

"""
Yields
------
yield_name : yield_type
    a good description of yield_name and how it relates to the next value
"""

Examples:

"""
Yields
------
str
    the value of the next alphabetic letter
"""

"""
Yields
------
error : tuple[int, Optional[str]]
    err_code : int
        Non-zero value indicates error code, or zero on success.
    err_msg : Optional[str]
        Human readable error message, or None on success.
"""

Receives Section

Syntax:

"""
Receives
--------
receive_type
    a good description of the value expected to be received and how it affects the generator
"""

"""
Receives
--------
receive_name : receive_type
    a good description of the value expected to be received and how it affects the generator
"""

Other Parameters Section

Syntax:

"""
Other Parameters
----------------
etc.
"""

Raises Section

Syntax:

"""
Raises
------
Exception1
    A good description of the exact circumstance(s) that would cause Exception1 to get thrown
Exception2
    A good description of the exact circumstance(s) that would cause Exception2 to get thrown
Etc.
"""

Warns Section

Syntax:

"""
Warns
-----
WarningName
    A good description of the circumstances that would cause WarningName
"""

Warnings Section

Syntax:

"""
Warnings
--------
- Don't do this one thing
- Don't do this other thing
- Be careful if you decide to do this thing
- Etc. etc. etc.
"""

See Also Section

Syntax:

"""
See Also
--------
other_func : optional super-short desc of what other_func does
package.other_module.other_submodule.func
Potentially longer description of the func
other_func1, other_func2, other_func3
"""

Notes Section

References Section

Examples Section

Docstrings for Classes

Class docstrings must include a description, an attributes section, and optionally, a methods section.

Example:

class Photo(ndarray):
    """
    Array with associated photographic information.

    Attributes
    ----------
    exposure : float
        Exposure in seconds.

    Methods
    -------
    colorspace(c='rgb')
        Represent the photo in the given colorspace.
    gamma(n=1.0)
        Change the photo's gamma exposure.
    """

Docstrings for Methods

Docstrings for Modules

Modules should at the very least include a summary in the docstring at the very top of the file

Sections:

  1. Summary (required, no section heading)
  2. Extended Summary (optional, no section heading)
  3. Constants (required for public constants, with heading)
  4. Routine Listings (optional, no section heading)
  5. See Also (optional, with heading)
  6. Notes (optional, with heading)
  7. References (optional, with heading)
  8. Examples (optional, with heading)

Additional Docstring Resources

autoDocstring VSCode Extension

For those of you who using VSCode for programming, there is an extension called autoDocstring, which can auto-format a templated layout of a docstring and auto-fill components based on type annotations. For this you have to set in the extension settings to use numpydoc.

Also, autoDocstring obviously won’t get everything, but very helpful and convenient to get a templated layout of the start to your docstring.

autoDocstring works by you typing triple quotes then pressing enter when you see the prompt.

A Note on NumPyDoc

For more information on numpydoc, reST (reStructuredText) markup, or some other examples of numpydoc, see the numpydoc docs

Do keep in mind that the documentation we’re using is slightly different than numpydoc in cases like constants don’t have their own docstrings, types are referenced with structural subtyping, and other smaller nuances.