AlgoMaster Logo

Docstrings

Medium Priority22 min readUpdated September 21, 2026
Listen to this chapter
Unlock Audio

A docstring is a string literal that lives at the top of a module, class, or function. Python treats it specially: it becomes the object's __doc__ attribute and shows up when someone runs help(). Docstrings are how Python code documents itself, and they're the source most documentation tools build from. This lesson covers what PEP 257 says, the three popular docstring styles, what to put in each section, and how to keep docstrings honest as code changes.

What a Docstring Is

The basic shape is a triple-quoted string as the first statement inside a module, class, or function:

That's a docstring. The string isn't a comment; it's an actual expression that Python evaluates, then attaches to the function as total.__doc__. You can read it programmatically:

The help() function shows the signature and the docstring together. IDEs use the same data to show tooltips, and documentation generators read __doc__ to produce reference pages. One string, several audiences.

A docstring belongs in three places:

  1. At the top of a module (the first statement in the .py file).
  2. Right after a class definition (the first statement in the class body).
  3. Right after a function or method definition (the first statement in the function body).

The module docstring at the top tells someone opening the file what they're looking at. The class docstring describes what Cart represents. Each method docstring describes what the method does. None of them is more than a line, which is fine: short and accurate beats long and stale.

PEP 257: The Conventions

PEP 257 is the docstring companion to PEP 8. It's a short document with rules about how to write docstrings, separate from the question of what content to put in them.

The rules that matter most:

  • Use triple double-quotes (`"""..."""`) for all docstrings, even one-liners. The reason is consistency: when you decide to add a multi-line section later, you don't have to change the quote style.
  • The first line is a summary, even for multi-line docstrings. It should fit on one line and end with a period.
  • For multi-line docstrings, the summary is followed by a blank line, then more detail.
  • Use the imperative mood for the summary: "Return the cart total" not "Returns the cart total." This matches the style of Python's own standard library and is the default in PEP 257.
  • End the docstring with `"""` on its own line for multi-line docstrings; for one-liners, the closing """ goes on the same line.

A one-line docstring:

A multi-line docstring:

The blank line between the summary and the body is mandatory. Without it, some doc tools fail to separate the summary from the rest, and the rendered output is wrong.

The shape is the same regardless of which docstring style you use. PEP 257 sets the skeleton; the styles fill in the body.

The Three Popular Styles

Once you go beyond a one-line summary, you usually want structured sections for arguments, return values, raised exceptions, and examples. Three styles dominate Python codebases.

Google Style

Google style uses readable section headers like Args:, Returns:, Raises:. The content under each header is indented.

Google style was originally documented in the Google Python Style Guide and was popularized by the napoleon Sphinx extension, which renders it cleanly. It's the most common style in modern Python code because it reads cleanly in the source: the section headers are English words, not punctuation-heavy markup. If a project doesn't already have a docstring style, Google style is the safest default.

NumPy Style

NumPy style was developed by the NumPy and SciPy community for scientific Python code. It uses section headers with an underline, similar to ReStructuredText section titles.

NumPy style takes more vertical space but is easier to scan in long docstrings with many parameters. It's the standard in scientific Python (NumPy, SciPy, scikit-learn, pandas) and shows up in any project that follows scientific conventions. The napoleon extension handles it alongside Google style, so picking one or the other is mostly a taste decision.

Sphinx (ReST) Style

Sphinx style uses ReStructuredText field lists with the :param:, :returns:, :raises: roles.

Sphinx style is the original format Sphinx understood without any extension. It's compact and works directly with Sphinx, but the :param: markers are heavy in the source compared to Google's plain headers. Most new code uses Google or NumPy style and lets napoleon convert it to ReST when Sphinx builds. Sphinx style still lives in older codebases and projects that haven't migrated.

Comparison

A side-by-side of the three styles, same function:

AspectGoogleNumPySphinx
Section headerArgs:Parameters\n----------(inline :param: markers)
Vertical spaceCompactGenerousMost compact
Readability in sourceHighHighLower (punctuation-heavy)
Tool supportnapoleon extensionnapoleon extensionNative Sphinx
Common inNew code, modern librariesScientific PythonOlder codebases

Pick one per project and stay with it. Mixing styles in the same codebase makes it hard for tools (and humans) to parse consistently. Many teams pick Google for new projects, NumPy if they're doing scientific work, and Sphinx style only if they already have it.

The Standard Sections

Most docstring styles support the same set of section types. The names differ slightly but the purpose is the same.

Args / Parameters

Describe each parameter, its meaning, and any constraints the type doesn't capture.

The description goes beyond what the type tells you. The type says customer_email is a str; the docstring explains what the string is used for. Constraints that aren't expressible in the type live here too: shipping_method accepts only two specific strings, and the docstring spells them out.

What not to include: a copy of the type annotation. With type hints in the signature, writing customer_email (str) in the docstring is duplication. Modern conventions drop the type from the docstring entirely and let the signature carry it.

Returns

Describe what the function returns. If the return type is obvious from the signature and the function name, a one-liner is enough. If there's something non-obvious (a tuple where each position means something specific, a dict with particular keys), spell it out.

The dict structure isn't obvious from -> dict, so the docstring documents the contract. A user reading the docs knows exactly which keys to expect.

Raises

List the exceptions the function can raise on purpose. You don't need to list every exception that could theoretically propagate from inner calls; just the ones the function itself raises explicitly or relies on as part of its contract.

The Raises: section is part of the function's contract. Users reading the docs know they should handle ValueError if they pass user input. Without the section, the only way to find out is to read the source or hit the error.

Examples

Examples show typical usage. They're powerful because they double as documentation and as tests if you use doctest.

The examples use the >>> prompt style that mimics the Python REPL. They show exactly what to expect when you call the function. Examples are useful when the function has a non-obvious behavior or when the parameter shapes need illustrating; for a trivial function, examples are overkill.

doctest: Examples That Run

Examples in docstrings can be more than documentation. Python's standard library ships with doctest, a module that runs the >>> examples and checks the output matches.

To run the doctests:

The benefit is that the examples in the docs can't drift. If you change the function and the example output changes, the doctest fails and you have to update the docstring. This is the lightest version of "test your docs."

The drawback is that doctests are brittle. Whitespace and floating-point precision matter, output that includes addresses (like <object at 0x10f3b2e80>) varies between runs, and anything stateful (file I/O, network calls) is hard to test this way. For a complex function, a real test in tests/ is better than a doctest. For a small pure function, doctests are quick to write and double as docs.

Doctests run the example code on every test run. If an example does anything expensive (large allocation, network call), it adds that cost to every doc-test run. Keep doctest examples cheap.

A common pattern: use doctests for the simplest, most illustrative examples that double as documentation; use regular tests for comprehensive coverage. The two complement each other.

Type Hints and Docstrings Together

Type hints changed what belongs in a docstring. Before type hints, the docstring had to describe types. Now the signature does:

The second version is shorter and says more. The types are in the signature where mypy or pyright can check them, and the docstring focuses on the non-obvious part (the convention that percent is a decimal, not a percentage).

The rule: don't repeat what the signature already says. Document what the type can't capture.

What types captureWhat docstrings should capture
price is a floatprice is in dollars, not cents
Returns a dictThe dict has keys 'item_count', 'subtotal', 'unique_items'
Takes a list[str]The list must be non-empty; order matters
Returns boolReturns True if the cart contains any in-stock item
Raises ValueErrorRaised when percent is outside [0, 1]

The right hand column is where the docstring adds value. Anything in the left column is already in the signature and doesn't need to be repeated.

Module and Class Docstrings

Most of the examples so far have been function docstrings. Modules and classes get docstrings too, with slightly different content.

Module Docstring

A module docstring sits at the top of the .py file as the very first statement. It tells someone opening the file what the module is for.

Module docstrings can be longer than function docstrings because they describe a whole file's worth of content. A typical structure: one-line summary, a paragraph or two of detail, and optionally a usage example.

What not to include: a copy of every function and class in the module. The auto-generated API reference handles that. The module docstring is a top-level orientation, not an index.

Class Docstring

A class docstring describes what the class represents. It goes right after the class line, before any methods.

The class docstring describes the class's purpose and any non-obvious behavior. The Attributes: section (Google style) lists public attributes, similar to how Args: lists parameters. You typically don't repeat __init__'s arguments here, but some codebases prefer to put the constructor's docs in the class docstring instead of in __init__. Either works as long as the project is consistent.

A common question is whether __init__ should have its own docstring or whether the class docstring should cover it. Both work. The Google style guide leans toward putting the constructor docs in the class docstring; the NumPy style guide leans toward giving __init__ its own. Pick one rule per project.

Enforcing Docstrings with Tools

Docstrings rot when nobody checks them. Three tools help.

pydocstyle and ruff D-rules

pydocstyle is a linter that checks docstrings against PEP 257. It catches missing docstrings, wrong quote styles, missing periods, and other PEP 257 violations.

The tool reports each violation with a code (like D100 for "missing docstring in public module") and a line number. You can configure which rules to enforce in pyproject.toml.

ruff integrates the same checks as its D rule category, so if you already use ruff you can enable docstring linting without a separate tool:

The convention setting tells ruff which docstring style you're using so it can apply the right rules. Set it to google, numpy, or pep257 to match your project's choice.

Consistency pays off twice here. Once you've picked Google style and told the linter, every new docstring gets checked against the same rules, and you catch slip-ups (missing Args: section, wrong indent) before they land.

Coverage of Docstrings

interrogate is a separate tool that reports what fraction of your public functions and classes have docstrings.

Useful in CI to enforce a minimum docstring coverage. Pair it with pydocstyle or ruff D-rules and you have two layers: docstrings exist, and the ones that exist are formatted correctly.

Pick a coverage threshold that's high enough to be useful but low enough that it doesn't punish reasonable exceptions. 80% is a common starting point; 100% is unrealistic for most codebases because some functions (test helpers, trivial private functions) don't need docstrings.

Type Hint Consistency

mypy or pyright won't check whether your docstring's Args: section matches the function's parameters, but tools like darglint will:

darglint reads the docstring, parses the Args: section, and compares it to the function signature. If a parameter is missing from the docstring, it flags it. If the docstring documents a parameter that doesn't exist, it flags that too. It's the closest you can get to forcing the docstring and the signature to stay in sync.

Combine the three tools and the workflow looks like this:

The three tools cover different angles: style, accuracy, coverage. None of them is enough on its own. Together they push the team to write docstrings, write them correctly, and keep them aligned with the code.

Practical Guidelines

A short list of habits that produce useful docstrings over time.

Write the summary first. The one-line summary is the most important part of any docstring. It's what shows up in tool tips, in help(), in autocomplete previews. Make it specific and use the imperative mood. "Return the cart total" is better than "This function returns the cart total" and much better than "Function for cart totaling."

Focus on WHY and edge cases. The signature with type hints already tells the reader the WHAT. The docstring's job is to fill in what the signature can't capture: unit conventions ("price is in dollars, not cents"), input constraints ("the list must be non-empty"), behavior under unusual inputs ("returns 0.0 for an empty cart"), and the non-obvious reasons the function exists.

Don't restate the obvious. A function called total() that returns a float doesn't need a docstring that says "Returns the total as a float." It needs a docstring that says "Return the subtotal of all items, before tax and shipping" because that's what the signature can't show.

Keep docstrings near the code. A docstring on apply_discount should describe what apply_discount does, not the entire discount module. Module-level concerns go in the module docstring. Class-level concerns go in the class docstring. Method docstrings stay focused.

Use one style per project. Whether you pick Google, NumPy, or Sphinx style, use it everywhere in the codebase. Mixing styles makes it harder for tools to parse and harder for humans to navigate.

Update the docstring in the same commit as the code. This is the biggest practice for keeping docstrings honest. A commit that changes a function signature without updating the docstring is the start of doc rot. Treating the two as a single change keeps drift from happening.

Don't document private internals. A function named _normalize_email is private (the leading underscore says so). A short docstring is fine; a full Args:/Returns:/Raises: treatment is overkill. Save the effort for the public API.

Quiz

Docstrings Quiz

10 quizzes