Comments & Documentation

Comments explain code to readers; docstrings turn documentation into introspectable data that tools like help() can read back — this topic covers both, plus the PEP 8 conventions that keep them consistent.

Code that works isn't the same as code that's understandable six months later, or to someone else on your team. Python gives you two distinct tools for this: comments (# text, ignored by the interpreter, meant purely for human readers) and docstrings (string literals placed where Python treats them specially, attaching documentation directly to modules, functions, and classes as inspectable data). This topic covers both, plus how to read documentation back with help() and __doc__.

Why Comment and Document Code?

Code explains what it does to a computer; comments and documentation explain why it does that to a human. Good documentation records intent, assumptions, and non-obvious reasoning that the code itself cannot express — the code shows how a rate limit is enforced, a comment can explain why that particular threshold was chosen. Because Python's syntax is already relatively readable, over-commenting obvious code is a common anti-pattern — comments earn their place by adding information the code doesn't already convey.

Single-Line Comments

A comment begins with # and runs to the end of the physical line; everything after # on that line is ignored by the interpreter entirely. Comments can stand alone on their own line or trail after code on the same line (an "inline comment").

PEP 8 recommends at least two spaces before an inline trailing comment, and a single space after the # before the comment text, as shown above.

# Compute the discounted price for a loyalty-program member
price = base_price * 0.9  # 10% loyalty discount

Block-Style Commenting Convention

A "block comment" is several consecutive #-prefixed lines used to explain a chunk of code that follows, rather than a single line. Python has no dedicated multi-line comment syntax (unlike C's /* ... */) — block comments are simply consecutive single-line comments, each starting its own line with #.

A plain triple-quoted string statement (like a stray "text" on its own line, not assigned to anything) is sometimes misused as a "comment block." It technically parses and does nothing useful at runtime for most purposes, but it is not idiomatic — use consecutive # lines for block comments; reserve triple-quoted strings for actual docstrings, described next.

# The retry loop below intentionally uses exponential backoff because the
# upstream API rate-limits aggressively and a fixed delay was found to
# trigger repeated 429 responses in production.
for attempt in range(MAX_RETRIES):
    ...

Docstrings — Documentation as Data

A docstring is a string literal (conventionally triple-quoted, """like this""") that appears as the very first statement inside a module, function, or class body. Unlike a comment, a docstring is not discarded by the interpreter — it is stored as that object's __doc__ attribute at runtime, which means documentation becomes data you (and tools) can retrieve programmatically, not just text a human reads in the source.

def area(radius: float) -> float:
    """Return the area of a circle with the given radius."""
    return 3.14159 * radius ** 2

print(area.__doc__)  # Return the area of a circle with the given radius.

Documenting Functions

A function's docstring should describe what it does, its parameters, and what it returns (and, if relevant, what it raises) — enough that a caller never needs to read the implementation to use it correctly. Multi-line docstrings conventionally start with a short one-line summary, a blank line, then further detail.

This follows the Google-style docstring convention, one of several popular third-party-tool-recognized styles (others include NumPy-style and reStructuredText/Sphinx-style).

def divide(a: float, b: float) -> float:
    """Divide a by b.

    Args:
        a: The numerator.
        b: The denominator; must be nonzero.

    Returns:
        The quotient a / b.

    Raises:
        ZeroDivisionError: If b is 0.
    """
    return a / b

Documenting Classes

A class docstring, placed as the first statement in the class body, describes what the class represents and how instances should be used. Methods within the class get their own individual docstrings for their specific behavior.

class Circle:
    """A circle defined by its radius, in arbitrary units."""

    def __init__(self, radius: float) -> None:
        """Create a circle with the given radius."""
        self.radius = radius

    def area(self) -> float:
        """Return this circle's area."""
        return 3.14159 * self.radius ** 2

Documenting Modules

A module's docstring is a string literal placed as the very first statement of the file, before even imports. It describes the module's overall purpose and is what shows up first when someone runs help(your_module) or inspects your_module.__doc__.

"""Utilities for computing areas and perimeters of basic 2D shapes."""

import math


def circle_area(radius: float) -> float:
    """Return the area of a circle with the given radius."""
    return math.pi * radius ** 2

Accessing Documentation: help() and __doc__

Because docstrings are stored as an object's __doc__ attribute, you can read them directly at runtime, either by accessing .__doc__ yourself or by calling the builtin help(), which formats the docstring (plus signature information) into readable output in the interactive interpreter.

Objects with no docstring have __doc__ equal to None. help() falls back to showing whatever signature information it can determine even without a docstring, but a missing docstring means far less useful output.

def area(radius: float) -> float:
    """Return the area of a circle with the given radius."""
    return 3.14159 * radius ** 2

print(area.__doc__)
help(area)
Return the area of a circle with the given radius.
Help on function area in module __main__:

area(radius: float) -> float
    Return the area of a circle with the given radius.

PEP 8 Documentation Conventions at a High Level

PEP 8 (Python's official style guide) and PEP 257 (specifically about docstring conventions) establish widely followed norms: use triple double-quotes """ for docstrings; write a concise one-line summary for simple functions, expanding to summary + blank line + details for anything more complex; end multi-line docstrings' closing """ on its own line for longer docstrings; keep comments up to date with the code they describe (a wrong comment is worse than no comment); and prefer clear code over an explanatory comment wherever the code can be made to speak for itself.

Complete Example

"""A small module for temperature conversions."""


def celsius_to_fahrenheit(celsius: float) -> float:
    """Convert a Celsius temperature to Fahrenheit.

    Args:
        celsius: Temperature in degrees Celsius.

    Returns:
        The equivalent temperature in degrees Fahrenheit.
    """
    # The standard linear conversion formula
    return celsius * 9 / 5 + 32


if __name__ == "__main__":
    print(celsius_to_fahrenheit(100))  # 212.0 — boiling point of water

Key Takeaways

Comments (#) are for human readers only — the interpreter discards them entirely and they carry no runtime data.

Docstrings are string literals as the first statement of a module, function, or class; they're stored as __doc__ and are inspectable at runtime.

Python has no multi-line comment syntax; block comments are just consecutive single-line # comments.

help() and __doc__ read docstrings back — write them assuming someone (or some tool) will read them without opening the source.

Comments should explain why, not restate what the code already says; a wrong or stale comment is actively harmful.

x = x + 1 # add one to x x = x + 1 # advance to the next retry attempt

A comment that just restates the code adds no information; a good comment explains the intent behind the line, which the code alone can't convey.

def total(items): "Return the total" return sum(items) def total(items: list[float]) -> float: """Return the total""" return sum(items)

Single quotes technically work as a docstring, but PEP 257 convention is triple double-quotes, which also allow the docstring to naturally span multiple lines if it later grows.

def fetch(url: str) -> dict: """Return the parsed response, or an empty dict on failure.""" ... return {}

A comment or docstring that no longer matches the code's actual behavior misleads readers worse than having no documentation at all — keep documentation updated alongside behavior changes.

What is the fundamental difference between a comment and a docstring in terms of how the interpreter treats them?

A comment (starting with #) is discarded entirely by the interpreter during parsing — it has no runtime existence at all. A docstring is an ordinary string literal that happens to be the first statement in a module, function, or class body, so the interpreter stores it as that object's __doc__ attribute, making it inspectable at runtime.

Where must a docstring be positioned within a function for Python to recognize it as the function's __doc__?

It must be the very first statement in the function body — a string literal, conventionally triple-quoted, immediately after the def line's colon, before any other code.

Does Python have true multi-line comment syntax like C's /* ... */? How do Python developers write block comments in practice?

No, Python has no dedicated multi-line comment syntax. Block comments are written as several consecutive lines that each individually start with #.

How would you programmatically retrieve the documentation string of a function named process_order, without using help()?

Access its __doc__ attribute directly: process_order.__doc__. This returns the docstring as a plain string (or None if the function has no docstring).

Why is a stale or incorrect comment considered worse than no comment at all?

A missing comment leaves a reader with no false expectations — they know they need to read the code. A stale comment actively misleads the reader into believing something about the code's behavior that is no longer true, which is more dangerous than an honest absence of documentation.

What does help(some_function) show if some_function has no docstring at all?

help() falls back to whatever signature information it can introspect (the function's name and parameters) but omits any descriptive body text, since there is no __doc__ content to display — the object's __doc__ is None in that case.

What does this print?

It prints: Return n squared. — the exact text of the docstring, retrieved via the function's __doc__ attribute.

Write a function named is_even that takes an integer and returns True if it's even, including a one-line docstring describing its behavior.

def is_even(n: int) -> bool: """Return True if n is even, False otherwise.""" return n % 2 == 0

The function returns n % 2 == 0, and its docstring — the first statement in its body — is retrievable via is_even.__doc__ or help(is_even).

Does VALUE = 1 or the # comment above it become part of this module's __doc__?

No. Only the triple-quoted string literal at the very top of the file becomes the module's __doc__. The # comment is discarded entirely by the interpreter and has no runtime representation at all.

Write a class Point with a class-level docstring and an __init__ method that stores x and y attributes, with its own docstring.

class Point: """A point in 2D space.""" def __init__(self, x: float, y: float) -> None: """Create a point at the given coordinates.""" self.x = x self.y = y

Point.__doc__ returns "A point in 2D space." and Point.__init__.__doc__ returns "Create a point at the given coordinates." — each docstring documents its own object independently.

def square(n):
    """Return n squared."""
    return n * n

print(square.__doc__)
"""This module has a module-level docstring."""

# This is just a comment, not a docstring
VALUE = 1