Comments & Docstrings
Comments let you leave notes in your code for other developers (and for your future self) without affecting how the program runs. Python gives you exactly one syntax for true comments, plus a widely used convention — the docstring — for attaching real, inspectable documentation to your code. This page walks through both, and shows how to write comments that actually help instead of getting in the way.
Single-line comments with #
Anything from a # character to the end of that physical line is a comment. The Python interpreter ignores it completely — it is not parsed, not executed, and has zero runtime cost. A comment can occupy its own line, or trail after a line of code.
# This is a full-line comment explaining the block below
total = 0
for price in [12.50, 4.25, 9.99]:
total += price # running total of the cart, updated per item
print(total) # 26.74A # inside a string literal is not a comment — Python only treats # as a comment marker when it appears outside of quotes. There is no way to comment out "the rest of this line only up to some point and then resume code" — once # appears, everything after it on that line is gone.
Why there is no block comment syntax
Languages in the C family (C, Java, JavaScript, CSS) provide a dedicated block-comment syntax — /* ... */ — that can span multiple lines and is understood by the compiler as pure, discardable text. Python deliberately has no equivalent. The language's design philosophy favors one obvious way to do a thing, and # already covers "ignore this text" for both single lines and, by repetition, many consecutive lines:
# This function validates a user's age.
# It rejects negative numbers and anything
# above a realistic human lifespan.
def validate_age(age):
return 0 <= age <= 130That said, developers frequently reach for a triple-quoted string ("""..."""or'''...'''`) as a stand-in for a "block comment" when they want to temporarily disable a chunk of code or leave a longer note. Because a standalone string literal expression that is not assigned to a variable and does nothing is legal but useless Python, the interpreter evaluates it and then throws the value away — effectively a no-op:
"""
Everything in this triple-quoted block is just a string literal.
It gets created in memory and then discarded because nothing
uses it. That side effect is what makes it *look* like a
multi-line comment, even though it isn't one.
"""
def process(data):
result = []
"""
print(f"debug: incoming data = {data}")
print("stepping through validation...")
"""
for item in data:
result.append(item.strip())
return resultDocstrings: real, inspectable documentation
A docstring is a triple-quoted string that is the very first statement in a module, function, class, or method. Unlike a regular comment, Python does not discard it — it is stored on the object's __doc__ attribute and remains available at runtime. This is what powers help(), IDE tooltips, and documentation generators like Sphinx.
def area_of_circle(radius):
"""Return the area of a circle with the given radius."""
return 3.14159 * radius ** 2
class Rectangle:
"""Represents an axis-aligned rectangle defined by width and height."""
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
"""Return the rectangle's area (width times height)."""
return self.width * self.heightDocstrings can document a module too — put the triple-quoted string as the first statement at the very top of the .py file, before any imports.
PEP 257: docstring conventions
PEP 257 is the style guide Python's own standard library follows for docstrings. Two shapes cover most cases:
One-line docstrings for simple, self-explanatory functions — a single sentence, on one line, phrased as a command ("Return the area...", not "Returns the area...")
Multi-line docstrings for anything with parameters, return values, exceptions, or non-obvious behavior — a one-line summary, then a blank line, then a more detailed body
def divide(numerator, denominator):
"""Divide two numbers and return the result.
Args:
numerator (float): The value to be divided.
denominator (float): The value to divide by. Must not be zero.
Returns:
float: The result of numerator / denominator.
Raises:
ZeroDivisionError: If denominator is 0.
"""
return numerator / denominatorThe Args/Returns/Raises layout above is "Google style." You will also encounter "NumPy style" (section headers underlined with dashes, e.g. Parameters / Returns) and reStructuredText style (:param name:, :returns:, :raises: field lists used by Sphinx). PEP 257 does not mandate any one of these — it only sets the baseline rules (summary line, blank line, closing quotes on their own line for multi-line docstrings). Pick one style per project and stay consistent; mixing styles in the same codebase makes automated doc tools inconsistent.
Accessing docstrings at runtime
Because docstrings are real string objects attached to the function, class, or module, you can read them from running code via the __doc__ attribute, or interactively via the built-in help() function.
def area_of_circle(radius):
"""Return the area of a circle with the given radius."""
return 3.14159 * radius ** 2
print(area_of_circle.__doc__)
help(area_of_circle)Return the area of a circle with the given radius.
Help on function area_of_circle in module __main__:
area_of_circle(radius)
Return the area of a circle with the given radius.help() formats __doc__ alongside the function's signature and is the fastest way to check how something works from a REPL session without leaving your terminal or opening a browser. The same pattern applies to classes and modules — try help(str) or help(list) to see documentation for built-in types.
Good comments vs. bad comments
Not all comments are equally useful. A comment that just restates what the code already says in plain syntax adds noise and maintenance burden — it has to be updated every time the code changes, and it rarely is. A good comment explains something the code cannot say for itself: the why behind a decision, a business rule, a non-obvious edge case, or a warning about something surprising.
Bad comment (restates the code) | Good comment (explains the why) |
|---|---|
increment ii += 1 | skip the header row before processingi += 1 |
set retries to 3retries = 3 | 3 retries matches the payment gateway's documented timeout policyretries = 3 |
loop through usersfor user in users: | process admins before regular users so audit logs stay orderedfor user in users: |
return truereturn True | treat an empty cart as "already checked out" to avoid double chargesreturn True |