Documenting modules and functions

The goal of documentation is to provide enough information for other programmers (or ourselves in six months!) to know how to use our code (that is to run a program, or import and use its components), and to understand it well enough to verify it and/or modify it.

So far our documentation has consisted of a block of header comments identifying the module and programmer, and occasional comments inserted into the code to explain tricky points. Modules and the functions in them require further documentation. The primary mechanism used to provide it is docstrings. These are triple quoted strings that appear at the top of the module and immediately after each function definition. Here's an artificial example,

# module_docn.py
'''This is the module documentation pointing out that
this is an artificial test module.'''

def test_fn_1():
    '''This is the first test function.
    It doesn't do anything.'''
    return

def test_fn_2():
    '''This is the second test function which also does nothing.'''
    return

In an actual module these docstrings would be helpful to a programmer reading your code by explaining what the module and each function in it were designed to do. You can see lots of real examples in the standard library modules.

Python also has built-in commands that extract this documentation. Recall that when we import a module in the shell we can use dir to see it's attributes. Here's an example for a real module, math,

>>> import math
>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__',
'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh',
'cbrt', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees',
'dist', 'e', 'erf', 'erfc', 'exp', 'exp2', 'exp1', 'fabs',
'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma','gcd',
'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt',
'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2',
'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod',
'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh',
'tau', 'trunc', 'ulp']
>>>

and here's the dir for our artificial module,

>>> import module_docn
>>> dir(module_docn)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__',
'__name__', '__package__', '__spec__', 'test_fn_1', 'test_fn_2']
>>>

You can see that in addition to the Python reserved names, i.e. __builtins__ to __package__ there are our two functions test_fn_1 and test_fn_2. We've already seen that the reserved name __name__ gives the current name of this module which will be module_docn if it has been imported or __main__ if it is running. Now let's see what __doc__ is,

>>> print(module_docn.__doc__)
This is the module documentation pointing out that
this is an artificial test module.
>>>

module_docn.__doc__ contains the module docstring. And now you may see why they are called docstrings: because they are the strings that get assigned to the __doc__ attributes. The docstrings for tst_fn_1 and test_fn_2 are also available in their __doc__ attributes,

>>> print(module_docn.test_fn_1.__doc__)
This is the first test function.
It doesn't do anything.
>>> print(module_docn.test_fn_2.__doc__)
This is the second test function.
It also doesn't do anything.
>>>

The docstrings are so useful but this is such a cumbersome way to access them that Python provides the built-in command help to provide easy access to them and improve the formatting of their display, e.g.

>>> help(module_docn)
Help on module module_docn:

NAME
module_docn

DESCRIPTION
This is the module documentation pointing out that
this is an artificial test module.

FUNCTIONS
test_fn_1()
    This is the first test function.
    It doesn't do anything.

test_fn_2()
    This is the second test function which also does nothing.

FILE
\\home\profiles\kreed\documents\cpsc128\programs\module_docn.py

>>>

All the information displayed is automatically extracted from the docstrings in the module. The pydoc module which is used behind the scenes by help is also used to produce much of the HTML Python documentation you encounter on the web. Just for completeness I will point out that help can also be used on an individual member function,

>>> help(module_docn.test_fn_1)
Help on function test_fn_1 in module module_docn:
test_fn_1()
This is the first test function.
It doesn't do anything.
>>>

or more usefully on real functions,

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

Return the square root of x.
>>>

Summary