COMPUTER PROGRAMMING 1 (PYTHON) • FUNCTIONS & MODULARITY

Function Docstrings — I can write a simple function docstring/spec describing inputs, outputs, and edge cases at my level.

Learn to document your functions so anyone can understand what they do, what they need, and what could go wrong.

Historical Context & Motivation

Imagine you write a function today that works perfectly. Six months later, you come back to it and have absolutely no idea what it does, what values it expects, or why you wrote it in the first place. This is not a hypothetical situation — it happens to professional developers all the time. The solution to this problem is documentation, and in Python, the primary tool for documenting functions is the docstring. A docstring is a special string placed right inside a function that describes what the function does, what inputs it expects, and what output it returns.

The idea of embedding documentation directly in source code has a rich history that traces back to the earliest days of programming. Before docstrings existed, programmers relied on separate manuals and comment blocks that often drifted out of sync with the actual code. Python's creator, Guido van Rossum, made documentation a first-class feature of the language from the very beginning, recognizing that code is read far more often than it is written.

1960s
Inline Comments Emerge
Early languages like FORTRAN and COBOL introduce comment syntax, allowing programmers to leave notes in their code. However, comments are ignored by the language entirely and have no structure.
1991
Python 0.9 Released
Guido van Rossum releases the first version of Python. The language already supports triple-quoted strings, which later become the foundation for docstrings.
2001
PEP 257 Published
Python Enhancement Proposal 257 establishes official conventions for writing docstrings, including formatting rules and best practices that are still followed today.
2010s
Auto-Documentation Tools
Tools like Sphinx and Read the Docs can automatically generate entire websites of documentation by reading docstrings directly from Python source code. This makes docstrings even more valuable.
2020s
AI-Assisted Coding
Modern AI coding assistants like GitHub Copilot use docstrings to understand what a function should do. Well-written docstrings help these tools generate better code suggestions.

The central question this lesson addresses is straightforward but important: How do you write clear, useful documentation inside a Python function so that anyone — including your future self — can understand what the function does? By the end of this lesson, you will be able to write a docstring that describes a function's purpose, its inputs, its outputs, and any tricky edge cases.

Core Principles of Docstrings

A docstring is a string literal that appears as the very first statement inside a function (or class, or module). Unlike regular comments that start with #, docstrings are enclosed in triple quotes ("""..""") and are actually stored as part of the function object. This means Python can access them at runtime through the special __doc__ attribute, and the built-in help() function can display them.

1

Purpose Statement

Every docstring should begin with a concise, one-line summary of what the function does. This line answers the question: "What does this function accomplish?"
2

Parameters (Inputs)

List each parameter the function accepts, including its name, expected data type, and a brief description of what it represents. This tells the caller exactly what to pass in.
3

Return Value (Output)

Describe what the function gives back. Include the data type and the meaning of the returned value. If the function returns None, state that explicitly.
4

Edge Cases

Document unusual or boundary inputs that could cause unexpected behavior — such as empty strings, negative numbers, or zero. This warns users about potential pitfalls.
5

Triple-Quote Syntax

Docstrings use triple double-quotes """ and must be the very first statement in the function body, placed on the line immediately after the def statement.
✦ KEY TAKEAWAY
Think of a docstring like the label on a medicine bottle. The label tells you what the medicine does (purpose), the correct dosage to take (inputs), the expected effect (output), and any warnings about side effects (edge cases). You would never take medicine without reading the label — and no one should use a function without being able to read its docstring.

Anatomy of a Docstring

The diagram below shows the structure of a well-written function with a complete docstring. Each colored section highlights a different part of the docstring, making it easy to see how the pieces fit together inside a real Python function.

This diagram shows a complete Python function with a docstring. The purple sections mark the purpose statement and closing quotes. The cyan section lists the inputs (parameters). The pink section describes the output. The amber section warns about edge cases.

Notice how the docstring begins on the line immediately after def calculate_average(numbers): and is indented to the same level as the function body. The opening """ starts the docstring, and the closing """ sits on its own line. Everything between those triple quotes is part of the documentation. The actual executable code comes afterward, starting with the if statement.

How Docstrings Work Under the Hood

Unlike regular comments (lines starting with #), Python does not throw away docstrings. When Python reads your function definition, it stores the docstring in a special attribute called __doc__. This means you can retrieve a function's documentation at any time while your program is running.

Accessing Docstrings at Runtime

There are two common ways to access a function's docstring. First, you can call help(function_name) in the Python interpreter, which displays the docstring in a nicely formatted way. Second, you can directly access function_name.__doc__ to get the raw string. Both approaches rely on the fact that Python stored the docstring internally when it first read the function definition.

💡 Comments vs. Docstrings
A # comment is completely ignored by Python — it's a note only visible when reading the source code. A docstring is stored as data inside the function object. Use comments for inline explanations of tricky lines. Use docstrings for the official description of what a function does.

One-Line vs. Multi-Line Docstrings

Simple functions can use a one-line docstring where the opening quotes, text, and closing quotes all fit on a single line, like """Return the square of a number.""". For functions that accept parameters and have edge cases, a multi-line docstring is appropriate. The multi-line version includes separate sections for Args, Returns, and Edge Cases, each clearly labeled and indented.

FeatureOne-Line DocstringMulti-Line Docstring
When to useSimple functions with no parameters or obvious behaviorFunctions with parameters, return values, and edge cases
LengthOne line, under 80 charactersMultiple lines with labeled sections
Example"""Return True if n is even."""See the diagram in Section 3

Identifying and Documenting Edge Cases

An edge case is an input that sits at the extreme boundary of what a function is designed to handle. These are the tricky situations where bugs tend to hide. For example, what happens if someone passes an empty list to a function that calculates an average? Or a negative number to a function that computes a square root? Documenting edge cases in your docstring warns the user about these potential pitfalls and shows that you have thought carefully about your function's behavior.

Six common categories of edge cases. When writing a docstring, scan this list and ask yourself which ones apply to your function. The empty input and wrong type categories are the most common for beginners to encounter.

You do not need to document every possible edge case — just the ones that are most likely or most dangerous. A good rule of thumb is to consider: what is the smallest valid input, the largest reasonable input, and any input of the wrong type? Documenting these three categories will cover the vast majority of situations.

  • Be specific: Instead of "handles bad input," write "raises ValueError if age is negative."
  • State the behavior: Say what the function actually does in the edge case — does it return a default value, raise an error, or skip the item?
  • Think like the caller: What would surprise someone using your function? Document that.

Worked Example: Writing a Complete Docstring

Let's walk through the process of writing a docstring for a function that finds the maximum value in a list of numbers. We will build the docstring piece by piece, following the four key components: purpose, inputs, output, and edge cases.

Writing a Docstring for find_max()
1
Step 1 — Write the Function SignatureStart by defining the function. We need a function called find_max that accepts one parameter: a list of numbers. The signature is def find_max(numbers):. On the very next line, we open the docstring with triple quotes.
def find_max(numbers): """
2
Step 2 — Write the Purpose StatementThe first line of the docstring should be a concise summary. Ask yourself: what does this function do in one sentence? It finds and returns the largest number in a given list. Keep it short and start with a verb.
"""Find and return the largest number in a list.
3
Step 3 — Document the ParametersAfter a blank line, add the Args section. List the parameter name, its expected type in parentheses, and a brief description. Our function takes one parameter: numbers, which should be a list of integers or floats.
Args: numbers (list of int or float): A list of numeric values to search through.
4
Step 4 — Document the Return ValueAdd a Returns section describing what comes back. Our function returns a single number — the largest value it found. Include the data type and meaning.
Returns: int or float: The largest value found in the list.
5
Step 5 — Document Edge CasesThink about boundary conditions. What if the list is empty? That would be a problem because there is no maximum of nothing. What if the list has only one element? Then the max is that element. We should document both situations clearly.
Edge Cases: - Raises ValueError if the list is empty. - Returns the single element if the list has only one item.
6
Step 6 — Assemble the Complete FunctionNow put it all together. Close the docstring with triple quotes on their own line, then write the function body. The complete function looks like this:
def find_max(numbers): """Find and return the largest number in a list. Args: numbers (list of int or float): A list of numeric values to search through. Returns: int or float: The largest value found in the list. Edge Cases: - Raises ValueError if the list is empty. - Returns the single element if the list has only one item. """ if len(numbers) == 0: raise ValueError("Cannot find max of empty list") largest = numbers[0] for num in numbers: if num > largest: largest = num return largest
🚀 Pro Tip
Try writing the docstring before you write the function body. This technique, sometimes called documentation-first development, forces you to think clearly about what the function should do before you get caught up in how to implement it.

Good vs. Bad Docstrings

Not all docstrings are created equal. A poorly written docstring can be worse than no docstring at all because it might mislead the reader. Let's compare examples of weak docstrings with strong ones to understand what separates effective documentation from lazy documentation.

Comparison of weak vs. strong docstrings across the four core components.
QualityBad Example ❌Good Example ✅
Purpose"""Does stuff.""""""Calculate the area of a circle given its radius."""
Inputs"""Takes a number."""Args: radius (float): The radius of the circle in cm.
Output"""Returns something."""Returns: float: The area in square centimeters.
Edge Cases(not mentioned at all)Edge Cases: - Raises ValueError if radius is negative.
✦ KEY TAKEAWAY
A good docstring answers three questions that a stranger looking at your function would ask: "What does this do?", "What do I pass in?", and "What do I get back?" If your docstring answers all three, you are in great shape. Adding edge case notes is the bonus that elevates your documentation from good to excellent.

Common mistakes include docstrings that simply repeat the function name ("This function does calculate_area"), docstrings that describe how the function works internally instead of what it does for the caller, and docstrings that are so long they become harder to read than the code itself. Keep your docstrings focused on the contract between the function and its caller: what goes in, what comes out, and what could go wrong.

Connection to Advanced Documentation

The simple docstring format you have learned here is the foundation for more advanced documentation practices used in professional Python development. As you grow as a programmer, you will encounter formal docstring styles like Google style, NumPy style, and reStructuredText (reST) style. Each one has slightly different formatting rules, but they all share the same core components you just learned: purpose, parameters, return values, and edge cases.

How the beginner docstring format maps to professional practices.
FeatureWhat You Learned (Beginner)Professional / Advanced
Purpose lineOne-sentence summaryOne-sentence summary (same!)
ParametersArgs section with name and typeFormal type hints plus detailed descriptions
Return valueReturns section with typeReturns + Yields for generators
Edge casesEdge Cases sectionRaises section listing specific exceptions
ExamplesNot required at this levelEmbedded runnable examples using doctest format
Auto-docsNot applicableTools like Sphinx generate HTML docs from docstrings

The good news is that the skills you are building now transfer directly. When you eventually use type hints (like def find_max(numbers: list[float]) -> float:) or write Raises sections listing specific exception types, you will already understand the underlying concept: clearly communicating the contract between a function and the code that calls it.

Practice Problems

PROBLEM 1 — CONCEPTUAL
What is the difference between a comment (using #) and a docstring (using """...""") in Python? Explain why a programmer would choose one over the other.
PROBLEM 2 — BASIC
Write a one-line docstring for the following function: def is_positive(n): return n > 0 Your docstring should follow the conventions discussed in this lesson.
PROBLEM 3 — INTERMEDIATE
Write a complete multi-line docstring for this function. Include the purpose, Args, Returns, and Edge Cases sections. def count_vowels(text): vowels = "aeiouAEIOU" count = 0 for char in text: if char in vowels: count += 1 return count
PROBLEM 4 — APPLIED
You are building a grade calculator for your school. Write both the function signature and a complete docstring for a function called letter_grade that takes a numeric score (0−100) and returns a letter grade (A, B, C, D, or F). Think carefully about what edge cases might arise in a real grading system.
PROBLEM 5 — CRITICAL THINKING
A classmate writes the following function and docstring. Identify at least three problems with the docstring and rewrite it so that it meets the standards from this lesson. def process(data): """This function processes the data.""" result = [] for item in data: if item >= 0: result.append(item ** 0.5) return result

Lesson Summary

A docstring is a triple-quoted string placed as the first statement inside a Python function that serves as its built-in documentation. Every effective docstring contains four core components: a purpose statement summarizing what the function does, an Args section listing each parameter's name, type, and description, a Returns section describing the output type and meaning, and an Edge Cases section warning about boundary inputs like empty lists, negative numbers, or wrong data types.

Unlike comments that Python ignores, docstrings are stored in the function's __doc__ attribute and can be retrieved at runtime with help(). Good docstrings start with a verb, are specific rather than vague, and focus on the contract between the function and its caller — what goes in, what comes out, and what could go wrong. These foundational skills translate directly into professional documentation practices like Google style and NumPy style docstrings used in industry.

Varsity Tutors • Computer Programming 1 (Python) • Function Docstrings