Python tutorials > Best Practices > Documentation > How to write docstrings?

How to write docstrings?

Docstrings are multiline strings used to document Python code. They serve as the official documentation for modules, classes, functions, and methods. This tutorial explores how to write effective docstrings following PEP 257 guidelines, including examples and best practices. A well-written docstring greatly improves code readability and maintainability.

What is a Docstring?

A docstring is a string literal that occurs as the first statement in a module, class, function, or method definition. It's accessed using the __doc__ attribute of the object. Docstrings explain what the code does and how to use it. They are used by documentation generators (like Sphinx) and interactive help systems.

Basic Docstring Example

This example shows a simple docstring for a function that adds two numbers. The docstring briefly describes what the function does. The __doc__ attribute allows you to access the docstring programmatically.

def add(x, y):
    """Return the sum of x and y."""
    return x + y

print(add.__doc__)

Multi-line Docstring Example

This example shows a multi-line docstring that adheres to a common structure. It includes a brief description, argument descriptions, and a return value description. Using structured formatting makes the docstring easier to parse and understand. PEP 257 recommends using triple double quotes (""") for docstrings.

def calculate_area(length, width):
    """Calculate the area of a rectangle.

    Args:
        length (int): The length of the rectangle.
        width (int): The width of the rectangle.

    Returns:
        int: The calculated area of the rectangle.
    """
    return length * width

print(calculate_area.__doc__)

Docstring Components: Summary Line

The first line of a docstring should be a concise summary of the object's purpose. It should be written in the imperative mood ('Do this', 'Return that'). It should also be a complete sentence and end with a period.

Docstring Components: Argument Description

Describe each argument's name, type, and purpose. Using consistent naming conventions (e.g., 'length (int): The length of the rectangle') makes the documentation easier to read. This section is often labeled 'Args:'.

Docstring Components: Return Value Description

Describe the type and purpose of the return value. This section is often labeled 'Returns:'. If the function raises an exception, describe the exception and under what circumstances it is raised.

Docstring Components: Raising Exceptions

Document exceptions that a function might raise. This helps users understand potential errors and how to handle them. Use the 'Raises:' section to clearly document exception conditions.

def divide(x, y):
    """Divide x by y.

    Args:
        x (int): The numerator.
        y (int): The denominator.

    Returns:
        float: The result of the division.

    Raises:
        ZeroDivisionError: If y is zero.
    """
    if y == 0:
        raise ZeroDivisionError("Cannot divide by zero.")
    return x / y

Google Style Docstrings

Google Style docstrings are a popular format that provides a standardized structure for describing arguments, returns, and exceptions. Libraries like TensorFlow and NumPy use this style. Many tools, like Sphinx with the napoleon extension, can automatically generate documentation from Google-style docstrings.

def example_function(arg1, arg2):
    """Does something.

    Args:
        arg1 (str): The first argument.
        arg2 (int): The second argument.

    Returns:
        bool: True if successful, False otherwise.

    Raises:
        ValueError: If something goes wrong.
    """
    # Function implementation here
    return True

NumPy/SciPy Style Docstrings

NumPy/SciPy style docstrings are another common format, particularly in scientific computing. They use a slightly different structure for describing arguments, returns, and exceptions. Sphinx with the numpydoc extension supports parsing this format.

def another_example(param1, param2):
    """Do something else.

    Parameters
    ----------
    param1 : str
        The first parameter.
    param2 : int
        The second parameter.

    Returns
    -------
    bool
        True if successful, False otherwise.

    Raises
    ------
    TypeError
        If the parameters have the wrong type.
    """
    return True

Real-Life Use Case Section: Documenting a Class

This example demonstrates documenting a class, including its attributes and methods. The class docstring describes the purpose of the class and lists its attributes. Each method also has its own docstring describing its function.

class Dog:
    """Represents a dog.

    Attributes:
        name (str): The name of the dog.
        breed (str): The breed of the dog.

    Methods:
        bark(): Prints the dog's bark.
    """
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    def bark(self):
        """Prints the dog's bark."""
        print("Woof!")

Best Practices: Consistency

Maintain a consistent style throughout your project. Choose a docstring style (e.g., Google, NumPy) and stick to it. Consistent documentation makes the code easier to understand and maintain.

Best Practices: Clarity

Write clear and concise docstrings. Avoid jargon and explain complex concepts in simple terms. The goal is to make the code understandable to others (and to your future self).

Best Practices: Completeness

Document all modules, classes, functions, and methods. Include descriptions of arguments, return values, and any exceptions that might be raised. Complete documentation ensures that all aspects of the code are covered.

Interview Tip: Docstring Knowledge

Understanding docstrings is a sign of a good Python developer. Be prepared to explain what docstrings are, why they are important, and how to write them effectively. Being able to articulate the value of documentation demonstrates your commitment to code quality.

When to Use Them: Always!

Write docstrings for all public interfaces: modules, classes, functions, and methods. Private functions (those starting with an underscore) can have shorter docstrings or be omitted, but it's still good practice to document them if they perform complex logic.

Alternatives: Comments

While comments are useful for explaining specific lines of code or complex logic within a function, they are not a substitute for docstrings. Docstrings are used for generating documentation and provide a higher-level overview of the code's purpose. Comments are typically for internal explanations.

Pros: Improved Readability

Well-written docstrings make code easier to read and understand, both for developers working on the code and for users who are using the code as a library.

Pros: Automatic Documentation Generation

Tools like Sphinx can automatically generate documentation from docstrings, making it easier to create and maintain comprehensive documentation for your project.

Pros: Interactive Help

Docstrings are used by Python's built-in help() function and IDEs to provide interactive help to users.

Cons: Time Investment

Writing good docstrings takes time and effort. However, the long-term benefits of improved code readability and maintainability outweigh the initial time investment.

Example: Using Sphinx to generate documentation

Sphinx is a powerful tool for generating documentation from docstrings. First, install sphinx: pip install sphinx. Then, install a theme like ReadTheDocs: pip install sphinx_rtd_theme. After that configure Sphinx to generate documentation by typing in the terminal: sphinx-quickstart in your project's folder. Follow the prompts to configure your project. Then edit the `conf.py` to include the needed extension: extensions = ['sphinx.ext.autodoc', 'sphinx_rtd_theme']. Finally generate the html files by typing make html in the terminal. Sphinx will automatically parse your docstrings and generate a beautiful and easy to navigate website.

FAQ

  • What is PEP 257?

    PEP 257 is a Python Enhancement Proposal that provides conventions for docstrings. It covers topics such as the format of docstrings, how to write summary lines, and how to document arguments and return values.
  • How do I access a docstring programmatically?

    You can access a docstring using the __doc__ attribute of the object (e.g., function.__doc__, class.__doc__, module.__doc__).
  • What's the difference between a comment and a docstring?

    Comments are used to explain specific lines of code or complex logic within a function, while docstrings are used to document the purpose of modules, classes, functions, and methods. Docstrings are used by documentation generators and interactive help systems, while comments are typically ignored by these tools.