| name | python-documentation-standards |
| description | Reference knowledge base for the python-doc-comments agent. Loaded by that agent on its first iteration when the host has not already injected it; not intended for direct invocation. |
Python Documentation Standards
A comprehensive guide to Python documentation following PEP 8, PEP 257, and modern best practices. This document serves as the knowledge base for the python-doc-comments pattern.
Table of Contents
- Core Principles
- Docstrings (PEP 257)
- Comments (PEP 8)
- Type Hints
- Codetags
- Magic Comments
- Linter Directives
- Common Mistakes
- When to Refactor Instead of Document
- Quality Checklist
Core Principles
The Golden Rules
| Principle | Description |
|---|
| Triple double quotes | Always use """ for docstrings |
| Complete sentences | Proper capitalization and punctuation |
| Explain "why" | Code shows "what", comments explain "why" |
| User focus | Document for users, not implementation |
| Synchronize | Outdated comments are worse than none |
| Use sparingly | Prefer clear code over excessive comments |
Philosophy
- Self-documenting code is the first priority
- Comments should add value, not state the obvious
- Type hints complement docstrings, not replace them
- Professional tone in all documentation
Docstrings (PEP 257)
Docstrings become the __doc__ attribute of modules, functions, classes, and methods.
One-Line Docstrings
For simple, obvious cases:
def kos_root():
"""Return the pathname of the KOS root directory."""
global _kos_root
return _kos_root
Rules:
- Closing quotes on the same line
- Imperative mood: "Return X" not "Returns X"
- End with a period
- No blank lines before or after
- Never restate the function signature — describe the return value's nature instead
- Use
r"""raw triple double quotes""" if backslashes appear in the docstring
Multi-Line Docstrings
For complex documentation:
def complex(real=0.0, imag=0.0):
"""Form a complex number.
Keyword arguments:
real -- the real part (default 0.0)
imag -- the imaginary part (default 0.0)
"""
if imag == 0.0 and real == 0.0:
return complex_zero
Structure:
- Summary line (fits on one line)
- Blank line
- Detailed description
- Closing quotes on separate line
Module Docstrings
"""A one-line summary of the module, terminated by a period.
Leave a blank line. The rest of this docstring should contain an
overall description of the module. Optionally, it may also contain
a brief description of exported classes and functions.
Typical usage example:
foo = ClassFoo()
bar = foo.function_bar()
"""
import os
import sys
Placement:
- Must be the first statement in the module
- Comes after magic comments (shebang, encoding)
- Comes before imports
Function/Method Docstrings (Google Style)
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
"""Fetch rows from a Bigtable.
Retrieve rows pertaining to the given keys from the Table instance
represented by big_table.
Args:
big_table: An open Bigtable Table instance.
keys: A sequence of strings representing the key of each table
row to fetch.
other_silly_variable: Another optional variable, that has a much
longer name than the other args.
Returns:
A dict mapping keys to the corresponding table row data fetched.
Each row is represented as a tuple of strings. For example:
{'Serak': ('Rigel VII', 'Preparer'),
'Zim': ('Irk', 'Invader')}
Raises:
IOError: An error occurred accessing the bigtable.Table object.
"""
pass
Sections:
| Section | Purpose |
|---|
| Args | List each parameter with description |
| Returns | Describe the return value and its type |
| Yields | For generators |
| Raises | Document exceptions that may be raised |
Class Docstrings
class SampleClass:
"""Summary of class here.
Longer class information and detailed description.
Attributes:
likes_spam: A boolean indicating if we like SPAM or not.
eggs: An integer count of the eggs we have laid.
"""
def __init__(self, likes_spam=False):
"""Initialize the instance based on spam preference.
Args:
likes_spam: Defines if instance exhibits this preference.
"""
self.likes_spam = likes_spam
self.eggs = 0
Key Points:
- Summarize what instances represent
- List public attributes in Attributes section
- Document
__init__ separately
Docstring Styles Comparison
Google Style (recommended):
def function(arg1: int, arg2: str) -> bool:
"""Summary line.
Args:
arg1: Description of arg1.
arg2: Description of arg2.
Returns:
Description of return value.
Raises:
ValueError: When validation fails.
"""
pass
NumPy Style (scientific computing):
def function(arg1: int, arg2: str) -> bool:
"""Summary line.
Parameters
----------
arg1 : int
Description of arg1.
arg2 : str
Description of arg2.
Returns
-------
bool
Description of return value.
Raises
------
ValueError
When validation fails.
"""
pass
Sphinx/reStructuredText Style:
def function(arg1: int, arg2: str) -> bool:
"""Summary line.
:param arg1: Description of arg1
:type arg1: int
:param arg2: Description of arg2
:type arg2: str
:return: Description of return value
:rtype: bool
:raises ValueError: When validation fails
"""
pass
Important: Do not mix styles within a project. Choose one and be consistent.
Sphinx Integration: For Google or NumPy style docstrings to work with Sphinx documentation, add the sphinx.ext.napoleon extension to your conf.py.
Comments (PEP 8)
Block Comments
Block comments apply to code that follows them.
active_users = [u for u in users if u.is_active]
return sorted(active_users, key=lambda u: u.registered_at)
Rules:
- Start with
# followed by a single space
- Indent to the same level as the code
- Separate paragraphs with a line containing only
#
Inline Comments
Inline comments appear on the same line as code. Use sparingly.
x = x + 1
discount = 0.9
x = x + 1
Rules:
- Separate from code by at least 2 spaces
- Start with
# and a single space
- Maximum 72 characters recommended
- Use sparingly - only when adding real value
When Comments Add Value
discount = 0.25 if user.is_grandfathered else 0.20
items.sort()
user_map = {user.id: user for user in users}
candidate = None
Type Hints
Type hints complement docstrings by providing static type information.
Basic Types
def greeting(name: str) -> str:
"""Return a greeting message."""
return f'Hello {name}'
Complex Types
from typing import List, Dict, Optional, Union
def process_items(
items: List[str],
config: Optional[Dict[str, Union[str, int]]] = None
) -> List[Dict[str, str]]:
"""Process items with optional configuration.
Args:
items: List of item names to process.
config: Optional configuration dictionary.
Returns:
List of processed item dictionaries.
"""
pass
Modern Python (3.10+)
def process(items: list[str], config: dict[str, str | int] | None = None) -> list[dict[str, str]]:
"""Process items with optional configuration."""
pass
Key Points
| Aspect | Description |
|---|
| Static analysis | Used by mypy, pyright, IDEs |
| Documentation | Human-readable, stays in code |
| Runtime | Type hints don't enforce at runtime |
| Combination | Use both type hints AND docstrings |
Codetags
Standardized annotations that flag code requiring attention.
Common Tags
| Tag | Purpose | Example |
|---|
TODO | Pending tasks | # TODO: Add input validation |
FIXME | Code needing fixes | # FIXME: Memory leak in loop |
XXX | Synonym for FIXME | # XXX: This breaks with unicode |
BUG | Known defects | # BUG: Tracked as JIRA-456 |
HACK | Temporary workarounds | # HACK: Works around API bug |
NOTE | Important clarifications | # NOTE: Requires Python 3.8+ |
Format with Metadata
def legacy_code():
pass
def leaky_function():
pass
Metadata Fields:
<initials> - Owner/author
d:date - Due date (ISO 8601)
p:0-3 - Priority (0=highest)
t:id - Tracker reference
Best Practices
- Include ownership (initials or name)
- Add context (ticket numbers, due dates)
- Be specific about the problem
- For serious issues, create tickets in issue tracker
- Keep TODOs temporary - fix or move to tracker
Magic Comments
Special comments that provide instructions to the interpreter.
Shebang Line
Rules:
- Must be the first line
#!/usr/bin/env python3 is portable (uses PATH)
- Only needed for executable scripts
Encoding Declaration (PEP 263)
Rules:
- Must be on first or second line
- Usually unnecessary (UTF-8 is default in Python 3)
- Required only for non-UTF-8 encodings
Complete File Header
"""Module docstring comes after magic comments.
This is the proper order for file headers in Python.
"""
import os
import sys
Linter Directives
Special comments to control static analysis tools.
Type Checking (mypy, pyright)
result = some_untyped_function()
value = process(wrong_type)
Style Checking (flake8)
long_line = "Very long line"
another_long_line = "Long line"
from module import unused
Linting (pylint)
very_long_line = "Intentionally long"
try:
risky()
except Exception:
handle()
Code Coverage
def debug_function():
"""Only used during development."""
print("Debug")
if __name__ == "__main__":
main()
Formatting (black)
matrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
]
Best Practices for Directives
- Be specific - use exact error codes
- Add explanations - why ignoring?
- Minimize scope - apply to smallest section
- Review regularly - suppressed warnings may hide issues
Common Mistakes
Redundant Comments
Bad:
x = x + 1
name = "John"
Good:
x = x + 1
Redundant Docstrings
Bad:
def add(a, b):
"""Add two numbers.
This function takes two numbers and adds them together.
It returns the sum of a and b.
"""
return a + b
Good:
def add(a, b):
"""Return the sum of a and b."""
return a + b
Commented-Out Code
Bad:
def current():
return new_way()
Good:
def current():
return new_way()
Lying Comments
Bad:
def get_username(user):
return user.email
Mumbling
Comments where the developer is talking to themselves rather than the reader. These add confusion instead of clarity.
Bad:
result = parse(data)
cache = {}
Apologetic Comments
Comments that apologize for bad code instead of fixing it.
Bad:
def process(data):
...
Solution: Clean up the code. If the code needs explanation, refactor it so it doesn't.
Over-Commenting
Bad:
def process_order(order):
if not order.is_valid():
raise ValueError("Invalid order")
total = order.calculate_total()
return total
Good:
def process_order(order):
if not order.is_valid():
raise ValueError("Invalid order")
return order.calculate_total()
Missing Type Context
Old way (duplicates type info):
def process_user(user):
"""Process a user.
Args:
user (dict): User dictionary with 'id', 'name', 'email'
Returns:
bool: True if successful
"""
pass
Modern way (types in signature):
from typing import TypedDict
class User(TypedDict):
id: int
name: str
email: str
def process_user(user: User) -> bool:
"""Process a user and update the database."""
pass
When to Refactor Instead of Document
Before writing a comment or docstring, ask: Can I make this clearer through code?
Heavy commenting often signals deeper issues. If you need long explanations to justify confusing code, refactor first.
Refactoring Alternatives
| Instead of... | Try... |
|---|
# Get the third item | category = row[2] or tuple unpacking |
# Check if valid | def is_valid_email(email): |
# Magic number for retry | MAX_RETRIES = 3 |
# Loop over items | Use descriptive variable names |
# Convert to uppercase | The code is already clear — delete the comment |
Five Alternatives to Comments
- Use descriptive names — rename functions or variables to clarify intent
- Extract unnamed code blocks — create helper functions with meaningful names
- Name embedded values — create constants for magic numbers and strings
- Apply tuple unpacking — replace index-based access with named variables
- Add or improve docstrings — use structured docstrings instead of inline comments
When Documentation Is Valuable
- Explaining "why" — business rules, edge cases, workarounds
- Linking to external references — bug tickets, specs, RFCs
- Warning about non-obvious behavior — side effects, gotchas
- TODO/FIXME — with ticket numbers for tracking
- Legal/licensing — copyright notices, license headers
- Complex algorithms — references to papers or explanations
Tools and Automation
Recommended Tools
pyproject.toml Configuration
[tool.black]
line-length = 88
[tool.mypy]
strict = true
[tool.pylint.messages_control]
max-line-length = 88
[tool.pydocstyle]
convention = "google"
Documentation Generators
| Tool | Description |
|---|
| Sphinx | Full documentation suite |
| MkDocs | Markdown-based docs |
| pdoc | Auto-generated API docs |
Quality Checklist
Docstrings
Comments
Type Hints
Tool Integration
Code Quality
References
Last updated: 2026-03-17