Docstrings

Documenting Modules, Classes and Functions well

Created: July 25th 2019
Updated: December 7th 2019
Connect with us on
image
image

Docstrings are an incredibly useful tool in anyone who writes python codes' toolbelt. They are great for letting people know how to use your code.

You should be using docstrings in EVERY class and function definition. Remember that even a poorly styled docstring is better than no context whatsoever so if you are in a hurry at least get the crucial usage details down.

Definitions

Some terms to help you navigate the post

Docstrings

Docstrings are used to document modules/files, classes, and functions. They help others to understand your code and use it. They are often integrated into IDE's to allow people (and yourself) to quickly see information about using your code including arguments for functions and class instantiation, as well as purpose.

They are also particularly useful for helping YOU to remember how your code works after not working on a code base for a while.

Although there are different styles they all follow the same layout outlined in PEP-257. The format for each type of docstring is as follows

Modules/files:

The layout for modules/files is to put the docstring at the top of the file encased in triple quotes. See docstrings.py for more details.

Functions

The layout for functions is to put the docstring right after the funcion declaration, the docstring can (should) include information about purpose, usage, arguments, and returm/yield values. For example:

def main(x,y):
    """
    Takes two arguments, both are ints that will be used to instantiate
    a math_operations instance and run it's add_x_y method.
    """
    example = math_operations(x,y) # Instantiate using provided x, y values
    example.add_x_y() # Run the math_operations instance add_x_y method

Classes

There are two optional layouts (note that both are often implemented in IDE's and autodocumentation generators).

The first layout is class definition followed on the next line by triple quotes and the information. For example:

class math_operations:
    """
    This class takes 2 arguments on instantiation to be used with the remaining class functions to complete simple math operations.
    """

The second layout is to use the class constructors' docstring to contain the class information.

class math_operations:
    def __init__(self, x, y):
        """
        This class takes 2 arguments on instantiation to be used with the remaining class functions to complete simple math operations.
        """
        # Assign arguments to instance variables
        self.x = x
        self.y = y

Style Guides

Style guides are conventions for formatting code. They are prevelant in all languages, there are a few different ones in python, I have outlined a couple of the more popular ones for python later in this file.

Usage

Although running the demos are not the point, you can run each file using python <filename>.py

Real World Applications

Docstrings (and documentation in general) are an essential part of large projects, without them code becomes completely unmanageable, especially for external contributors.

Additional information

PEP-8

PEP-8 is a popular python style guide, it is very useful for styling python code. Particularly for this demo https://www.python.org/dev/peps/pep-0008/#documentation-strings may be helpful.

Docstring styles

There are multiple different 'styles' of docstrings, although (as far as I know) there is no official 'style' I have provided information on the three most popular styles below.

reStructuredtext Style

This style is often the 'preffered' style in the python community as it is the most prominent style used for sphinx (http://www.sphinx-doc.org/en/master/index.html) autodocumentation.

For more details about reStructuredtext. SEE: http://docutils.sourceforge.net/rst.html

Example function:

def main(x,y):
    """
    Instantiates a math_operations instance using the provided values and runs the instance add_x_y method.

    :param x: an arbitrary number to be used in instantiating a math_operations instance
    :type x: int or float

    :param y: an arbitrary number to be used in instantiating a math_operations instance
    :type y: int or float
    """

Google Style

This style is my preffered style for it's easy readability and flexibility.

For more details about the full google style guide. http://google.github.io/styleguide/pyguide.html

For details about google style docstrings http://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings

Example function:

def main(x,y):
    """
    Instantiates a math_operations instance using the provided values and runs the instance add_x_y method.

    Args:
        x(int or float): an arbitrary number to be used in instantiating a math_operations instance
        y(int or float): an arbitrary number to be used in instantiating a math_operations instance
    """

numpy Style

This style is used heavily in scientific and complex caculation libraries.

For details about numpy style docstrings https://numpydoc.readthedocs.io/en/latest/format.html

Example function:

def main(x,y):
    """
    Instantiates a math_operations instance using the provide values and runs the instance add_x_y method.

    Parameters
    ----------
        x : int or float
            an arbitrary number to be used in other instance methods
        y : int or float
            an arbitrary number to be used in other instance methods
    """

Files

docstrings_demo.py

""" This is the module/file docstring, this is where you put
information about the module/file purpose, as well as information
about any global variables.
NOTE: There are many different 'styles' of docstrings, there are
examples of the same class & function(s) in some of the different
styles found in the other files in this directory.
"""

# NOTE: it's also worth noting that some people include metadata at the top of their files like author, maintainers etc.

# SEE: http://epydoc.sourceforge.net/manual-fields.html#module-metadata-variables
# For example:
__author__ = "Canadian Coding"
__license__ = "MIT"
__date__ = "2019-07-19"
__version__ = "0.0.1"

class MathOperations:
    """
    This is the class docstring, here you can put info about class
    variables, relevant documentation reference(s), and basic 'quick start'
    info. You can also mention the purpose of the class here, For example:
    This class takes 2 arguments on instantiation to be used with the
    remaining class functions to complete simple math operations.
    """
    def __init__(self, x, y):
        """
        Class constructor, takes 2 arguments of arbitrary ints to be
        used with the other class methods after instantiation.
        """
        # Assign arguments to instance variables
        self.x = x
        self.y = y

    def add_x_y(self):
        """
        Takes the provided instance variables, adds them and prints
        and returns the result.
        """
        print(f"The result of {self.x} + {self.y} is {self.x+self.y}")
        return self.x+self.y


def main(x,y):
    """
    This is a function docstring, it can be used to provide information
    about function usage, arguments, and function purpose. For example:
    Takes two arguments, both are ints that will be used to instantiate
    a math_operations instance and run it's add_x_y method.
    """
    example = math_operations(x,y) # Instantiate using provided x, y values
    example.add_x_y() # Run the math_operations instance add_x_y method

if __name__ == "__main__":
    main(4,4)

google_style_demo.py

""" This file is here to demonstrate the Google style of docstrings.
This style is my preffered style for it's easy readability and flexibility.
For more details about the full google style guide.
SEE: http://google.github.io/styleguide/pyguide.html
For details about google style docstrings
SEE: http://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings
"""
class MathOperations:
    """
    There are two options for documenting the overall class. You can include
    all the information about the class purpose, instance/class paramaters, and
    contructor details, before the __init__ mehod or as the __init__ methods' docstring.
    In this example file I have done both. Also notice that when using the docstring outside
    the __init__ method the heading changes from Args to attributes.
    Attributes:
    x(int or float): an arbitrary number to be used in other instance methods
    y(int or float): an arbitrary number to be used in other instance methods
    """
    def __init__(self, x, y):
        """
        There are two options for documenting the overall class. You can include
        all the information about the class purpose, instance/class paramaters, and
        contructor details, before the __init__ mehod or as the __init__ methods' docstring.
        In this example file I have done both.
        Args:
        x(int or float): an arbitrary number to be used in other instance methods
        y(int or float): an arbitrary number to be used in other instance methods
        """
        # Assign arguments to instance variables
        self.x = x
        self.y = y

    def add_x_y(self):
        """
        Takes the provided instance variables, adds them and prints
        and returns the result.
        Returns:
        int: The result of adding the instances x and y variables
        """
        print(f"The result of {self.x} + {self.y} is {self.x+self.y}")
        return self.x+self.y

def main(x,y):
    """
    Instantiates a math_operations instance using the provided values
    and runs the instance add_x_y method.
    Args:
    x(int or float): an arbitrary number to be used in instantiating a math_operations instance
    y(int or float): an arbitrary number to be used in instantiating a math_operations instance
    """
    example = math_operations(x,y) # Instantiate using provided x, y values
    example.add_x_y() # Run the math_operations instance add_x_y method

if __name__ == "__main__":
    main(4,4)

numpy_style_demo.py

""" This file is here to demonstrate the Numpy style of docstrings.
This style is used heavily in scientific and complex caculation libraries.
For details about numpy style docstrings
SEE: https://numpydoc.readthedocs.io/en/latest/format.html
"""
class MathOperations:
    """
    There are two options for documenting the overall class. You can include
    all the information about the class purpose, instance/class paramaters, and
    contructor details, before the __init__ mehod or as the __init__ methods' docstring.
    In this example file I have done both. Also notice that when using the docstring outside
    the __init__ method the heading changes from Parameters to Attributes.
    Attributes
    ----------
    x : int or float
    an arbitrary number to be used in other instance methods
    y : int or float
    an arbitrary number to be used in other instance methods
    """
    def __init__(self, x, y):
        """
        There are two options for documenting the overall class. You can include
        all the information about the class purpose, instance/class paramaters, and
        contructor details, before the __init__ mehod or as the __init__ methods' docstring.
        In this example file I have done both.
        Parameters
        ----------
        x : int or float
        an arbitrary number to be used in other instance methods
        y : int or float
        an arbitrary number to be used in other instance methods
        """
        # Assign arguments to instance variables
        self.x = x
        self.y = y

    def add_x_y(self):
        """
        Takes the provided instance variables, adds them and prints
        and returns the result.
        Returns
        -------
        int or float
        The result of adding the instances x and y variables
        """
        print(f"The result of {self.x} + {self.y} is {self.x+self.y}")
        return self.x+self.y

def main(x,y):
    """
    Instantiates a math_operations instance using the provided values
    and runs the instance add_x_y method.
    Parameters
    ----------
    x : int or float
    an arbitrary number to be used in other instance methods
    y : int or float
    an arbitrary number to be used in other instance methods
    """
    example = math_operations(x,y) # Instantiate using provided x, y values
    example.add_x_y() # Run the math_operations instance add_x_y method

if __name__ == "__main__":
    main(4,4)

restructuredtext_style_demo.py

""" This file is here to demonstrate the reStructured Text style of docstrings.
This style is often the 'preffered' style in the python community as it is the most
prominent style used for sphinx (http://www.sphinx-doc.org/en/master/index.html) autodocumentation.
For more details about reStructuredtext.
SEE: http://docutils.sourceforge.net/rst.html
For details about docstrings in general SEE: docstrings.py and readme.md
"""
class MathOperations:
    """
    There are two options for documenting the overall class. You can include
    all the information about the class purpose, instance/class paramaters, and
    contructor details, before the __init__ mehod or as the __init__ methods' docstring.
    In this example file I have done both.
    :param x: an arbitrary number to be used in other instance methods
    :type x: int or float
    :param y: an arbitrary number to be used in other instance methods
    :type y: int or float
    """
    def __init__(self, x, y):
        """
        There are two options for documenting the overall class. You can include
        all the information about the class purpose, instance/class paramaters, and
        contructor details, before the __init__ mehod or as the __init__ methods' docstring.
        In this example file I have done both.
        :param x: an arbitrary number to be used in other instance methods
        :type x: int or float
        :param y: an arbitrary number to be used in other instance methods
        :type y: int or float"""
        # Assign arguments to instance variables
        self.x = x
        self.y = y

    def add_x_y(self):
        """
        Takes the provided instance variables, adds them and prints
        and returns the result.
        :returns: The result of adding the instances x and y variables
        :rtype: int
        """
        print(f"The result of {self.x} + {self.y} is {self.x+self.y}")
        return self.x+self.y

def main(x,y):
    """
    Instantiates a math_operations instance using the provided values
    and runs the instance add_x_y method.
    :param x: an arbitrary number to be used in instantiating a math_operations instance
    :type x: int or float
    :param y: an arbitrary number to be used in instantiating a math_operations instance
    :type y: int or float
    """
    example = math_operations(x,y) # Instantiate using provided x, y values
    example.add_x_y() # Run the math_operations instance add_x_y method

if __name__ == "__main__":
    main(4,4)

Thank you for your support!

Be sure to share the post if it was helpful!