Docstrings, comments & types

Writing Useful Comments in Python: What PEP 8 Says and What Helps Readers

Docstrings, comments & types · · Published 2026-10-27

Close-up of a medieval handwritten manuscript page in brown ink, with notes squeezed into the margin of the facing page
A page from a medieval composite manuscript, Basel University Library, A VII 42. Public domain.

Comments are the one part of a program that the interpreter never checks. That is their strength, because they can say things code cannot, and their weakness, because nothing stops them from becoming wrong. PEP 8 has a short section on comments; most of what makes one useful comes from asking who will read it and what they will need.

The rules in PEP 8

PEP 8's comment section is brief and mostly about form:

pycodestyle checks the mechanical parts: E261 (fewer than two spaces before an inline comment), E262 (inline comment not starting with # ), E265 (block comment not starting with # ) and E266 (block comment starting with ##).

x = 1 # bad: one space before the comment
y = 2  #bad: no space after the hash
#bad block comment
### decorative heading

The rule that matters most

The comments section of PEP 8 opens with its most important sentence: "Comments that contradict the code are worse than no comments. Always make a priority of keeping the comments up-to-date when the code changes!" A missing comment costs the reader some time; a wrong one sends them in the wrong direction with confidence. In review, a change to a function's behaviour should come with a look at the comments around it.

PEP 8 gives a small example of the difference between a useless and a useful inline comment:

x = x + 1  # Compensate for border

"Increment x" would only repeat the code. "Compensate for border" tells the reader something the code cannot: the reason.

Explain why, not what

Good names and small functions already say what the code does. Comments earn their place by carrying information that is not in the code:

TIMEOUT = 25  # Seconds. The upstream gateway closes idle connections at 30.

# Sort by date first, then by amount: the bank statement lists
# same-day transactions in amount order, and reconciliation
# relies on matching that order.
rows.sort(key=lambda row: (row.date, row.amount))

When you find yourself writing a comment that explains what a block does, consider whether the block should be a function whose name says it. apply_late_fee(invoice) needs no comment; ten lines under "# apply late fee" do.

TODOs, notes and tool directives

Comments also carry messages to people and tools.

Commented-out code

Blocks of code disabled with # are a common sight and almost never useful. They are not run, so they rot; they are not explained, so nobody knows whether they can be deleted; and they make searches return false matches. Version control already keeps every previous version. If code might be needed again, say so in a commit message or an issue, and delete it. ruff can flag commented-out code with its ERA001 rule, derived from the eradicate tool.

Comments versus docstrings

The two are often confused, but they have different readers:

DocstringComment
ReaderSomeone calling the codeSomeone changing the code
ContentWhat it does, arguments, return value, errorsHow and why the implementation works this way
Where it shows uphelp(), editors, generated docsOnly in the source
ConventionPEP 257PEP 8, "Comments"

PEP 8 connects the two: public functions get docstrings, while non-public methods can make do with a comment after the def line that describes what they do. Our guide to docstrings and PEP 257 covers the first column.

A quick self-review

  1. Does each comment say something the code does not?
  2. Is each one still true after your change?
  3. Could a better name or an extracted function replace it?
  4. Are TODOs linked to something that will get them done?
  5. Is there commented-out code to delete?

The checker on our home page reports E261, E262, E265 and E266 for a pasted snippet. The rest of this list is the kind of thing a reviewer catches; our guide to readable Python code develops the idea that names and structure should carry most of the meaning.

Sources