Skip to main content

Docstrings and Type Hinting: Documenting Your Functions

Writing code that works is only half the battle. Writing code that you and others can understand months from now is just as important. This is where documentation comes in. In this article, we'll explore two powerful, related concepts for documenting your Python functions: docstrings and type hints. Mastering them will elevate the quality and professionalism of your code.


📚 Prerequisites

This article builds on our previous discussions. You should be familiar with:

  • Defining functions with parameters and return values.
  • Python's basic data types (str, int, float, list, dict).

🎯 Article Outline: What You'll Master

In this article, you will learn:

  • Docstrings: What they are and how they differ from regular comments.
  • Docstring Formats: How to write clean, multi-line docstrings using the popular Google style.
  • Type Hinting: How to add type annotations to your function signatures to improve clarity and catch bugs.
  • The typing Module: Using advanced types like List, Dict, and Optional.
  • Combining Both: How to write a perfectly documented function using both docstrings and type hints.

🧠 Section 1: What are Docstrings?

A docstring (documentation string) is a string literal that occurs as the first statement in a module, function, class, or method definition. Its purpose is to explain what the code does.

How is it different from a comment?

  • Comments (#) are for the developers reading the code. They are ignored by the Python interpreter.
  • Docstrings ("""...""") are for the users of your code. They are attached to the function object itself and can be accessed at runtime.
def my_function():
"""This is a docstring. It explains the function's purpose."""
# This is a comment. It's for implementation notes.
pass

print(my_function.__doc__)
# Output: This is a docstring. It explains the function's purpose.

Tools like IDEs and documentation generators use docstrings to provide help and context about your code automatically.


💻 Section 2: Writing Effective Docstrings

While there are many formats, one of the most readable and popular is the Google Style. It uses simple sections to describe the different parts of your function.

2.1 - One-Line Docstrings

For very simple functions, a single line is enough. It should be a complete sentence that ends with a period.

def add(a, b):
"""Adds two numbers together."""
return a + b

2.2 - Multi-Line Docstrings (Google Style)

For anything more complex, a multi-line docstring is necessary. It has a summary line, followed by a more detailed description and sections for arguments and return values.

def calculate_sale_price(original_price, discount_percent, is_member):
"""Calculates the final price after applying a discount.

A special additional discount is applied for members.

Args:
original_price (float): The starting price of the item.
discount_percent (float): The standard discount percentage (e.g., 20.0 for 20%).
is_member (bool): True if the customer is a loyalty member.

Returns:
float: The final calculated price.
"""
discount = original_price * (discount_percent / 100)
if is_member:
discount += original_price * 0.05 # Extra 5% for members
return original_price - discount

This format is clean, easy to read, and provides all the essential information a user would need to use your function correctly without having to read the source code.


🛠️ Section 3: Improving Clarity with Type Hinting

Python is a dynamically-typed language, which means you don't have to declare a variable's type. This is flexible, but it can also lead to bugs that are hard to find.

Type Hinting (introduced in Python 3.5) allows you to annotate your code with the expected data types. These are just "hints" and are not enforced by the Python interpreter itself, but they are used by external tools called static type checkers (like Mypy) to find errors before you even run your code.

The syntax is straightforward:

  • For parameters: parameter_name: type
  • For return values: -> type

Let's add type hints to our add function:

def add(a: int, b: int) -> int:
"""Adds two numbers together."""
return a + b

Now, it's crystal clear that this function is intended to work with integers. If you try to call it with strings, a type checker will warn you.

add(5, 10)      # Correct
add("a", "b") # A type checker would flag this as an error

🚀 Section 4: Advanced Type Hinting with the typing Module

For more complex types, Python provides the typing module.

  • List, Dict, Set, Tuple: For collections.
  • Optional: For values that can be None. Optional[str] is shorthand for Union[str, None].
  • Union: For values that could be one of several types.
  • Any: For when you truly don't know or care about the type (use this sparingly!).

Let's rewrite our calculate_sale_price function with full type hints.

from typing import Union

def calculate_sale_price(
original_price: float,
discount_percent: float,
is_member: bool
) -> float:
"""Calculates the final price after applying a discount.

A special additional discount is applied for members.

Args:
original_price: The starting price of the item.
discount_percent: The standard discount percentage (e.g., 20.0 for 20%).
is_member: True if the customer is a loyalty member.

Returns:
The final calculated price.
"""
# Note: We removed the types from the docstring Args
# because the type hints in the signature are now the source of truth.
discount = original_price * (discount_percent / 100)
if is_member:
discount += original_price * 0.05
return original_price - discount

Notice that when you use type hints in the function signature, you can often remove them from the docstring's Args section to avoid redundancy. The docstring can then focus on explaining what the parameter is for, while the type hint explains what type it is.


✨ Conclusion & Key Takeaways

Docstrings and type hints are the cornerstones of writing professional, maintainable Python code. They make your functions easier to understand, easier to use, and less prone to bugs.

Let's summarize the key takeaways:

  • Docstrings are for Users: They explain the why and how of your function and can be accessed at runtime. Use a standard format like Google Style.
  • Type Hints are for Tools (and Humans!): They specify the what (the data types) and allow static analysis tools to catch errors early.
  • They Work Together: Use both to create a complete picture of your function's purpose and usage. The function signature provides the types, and the docstring provides the context.

Challenge Yourself: Write a fully documented function called create_greeting. It should take a name (string) and an optional age (integer) as arguments. If the age is provided, it should return a string like "Hello name, you are age years old!". If not, it should just return "Hello name!". Use type hints (including Optional) and a Google-style docstring.


➡️ Next Steps

We are nearing the end of our deep dive into functions. The final piece of the puzzle is understanding lambda functions, which allow you to create small, anonymous functions on the fly. We'll explore them in the next article: "Lambda Functions."

Happy documenting!


Glossary (Python Terms)

  • Docstring: A string literal used to document a Python object.
  • Type Hint: An annotation that specifies the expected data type of a variable, parameter, or return value.
  • Static Type Checker: An external tool (like Mypy) that analyzes code with type hints to find potential errors without running the code.
  • typing module: A standard library module that provides support for advanced type hints.

Further Reading (Python Resources)