Technology  /  Python

🐍 Python 78 guides · updated 2026

From first variable to OOP, generators, and real projects — the language that runs everything from data pipelines to AI agents, taught the practical way.

Python Comments and Docstrings: Writing Code That Explains Itself

There’s a version of every programmer who has opened their own code six months later and had no idea what it did. Comments and docstrings are how you write to that future person — whether it’s you or a teammate.

Python has two distinct mechanisms for this: comments, which the interpreter ignores entirely, and docstrings, which become part of the program and can be accessed at runtime.


Comments

Comments explain what the code is doing and, more importantly, why. The # symbol starts a comment; everything to the right of it on that line is ignored by Python.

# Calculate compound interest
principal = 1000
rate = 0.05
years = 10
amount = principal * (1 + rate) ** years # formula: P(1 + r)^t

The inline comment on the last line explains the formula — useful because ** isn’t universally recognised as “raise to the power of.”

When to comment and when not to

The classic mistake is commenting the obvious:

# Set x to 5
x = 5
# Print the result
print(result)

These comments add noise without adding information. Instead, comment on things that aren’t self-evident from the code:

# Offset by 1 because the API uses 1-based page numbering
page = requested_page + 1
# We intentionally skip rows where status is null — they're incomplete imports
filtered = [row for row in data if row["status"] is not None]

TODO and FIXME comments

It’s common practice to mark incomplete or problematic code with special comment tags:

# TODO: Add retry logic for network timeouts
response = requests.get(url)
# FIXME: This assumes sorted input — breaks if called with unsorted data
def find_first_match(items, target):
...

Most editors and tools recognise TODO and FIXME and can aggregate them. Just make sure you actually come back to fix them.


Docstrings

Docstrings are string literals placed immediately after a function, class, method, or module definition. They describe what the thing does, what arguments it expects, and what it returns. Unlike comments, docstrings persist at runtime and are accessible via .__doc__ or help().

def calculate_bmi(weight_kg, height_m):
"""Calculate Body Mass Index from weight and height.
Args:
weight_kg (float): Weight in kilograms.
height_m (float): Height in metres.
Returns:
float: BMI value rounded to one decimal place.
Raises:
ValueError: If height_m is zero or negative.
"""
if height_m <= 0:
raise ValueError("Height must be a positive number")
return round(weight_kg / height_m ** 2, 1)

Accessing the docstring at runtime:

print(calculate_bmi.__doc__)
help(calculate_bmi)

One-line docstrings

For simple functions where the purpose is obvious and there’s nothing to explain about arguments or return values, a single-line docstring is appropriate:

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

The closing """ goes on the same line. No blank lines before or after.

Multi-line docstrings

For anything more complex, use a multi-line format. The first line is a brief summary, followed by a blank line, then the details:

def parse_config(filepath, encoding="utf-8"):
"""Load and validate a YAML configuration file.
Reads the file at ``filepath``, parses it as YAML, and validates
required keys. Returns a dictionary. Raises ``ConfigError`` if
required keys are missing or the file cannot be parsed.
Args:
filepath (str): Absolute or relative path to the config file.
encoding (str): File encoding. Defaults to 'utf-8'.
Returns:
dict: Parsed configuration as a Python dictionary.
Raises:
FileNotFoundError: If the file does not exist.
ConfigError: If required keys are missing from the config.
"""
...

Class docstrings

Docstrings on classes should describe the class overall, not the __init__ method. Document __init__ separately if its arguments need explanation:

class DatabaseConnection:
"""Manages a persistent connection to a PostgreSQL database.
Handles connection pooling, automatic reconnection on failure,
and query execution with parameterised inputs.
Attributes:
host (str): Database server hostname.
port (int): Database server port.
connected (bool): True if the connection is currently active.
"""
def __init__(self, host, port=5432):
"""Initialise the connection with host and port.
Args:
host (str): Database server hostname.
port (int): Server port. Defaults to 5432.
"""
self.host = host
self.port = port
self.connected = False

Docstring Formats

Three common styles exist in the Python ecosystem:

Google style (widely used, readable):

def send_email(recipient, subject, body):
"""Send an email to the specified recipient.
Args:
recipient (str): Email address of the recipient.
subject (str): Subject line.
body (str): Message body (plain text).
Returns:
bool: True if the email was sent successfully.
"""

NumPy style (common in scientific Python):

def normalise(array):
"""Normalise array values to the range [0, 1].
Parameters
----------
array : list or numpy.ndarray
Input data to normalise.
Returns
-------
numpy.ndarray
Normalised array.
"""

reStructuredText / Sphinx style (used for auto-generated docs):

def get_user(user_id):
"""Retrieve a user by ID.
:param user_id: The unique identifier.
:type user_id: int
:returns: User object or None.
:rtype: User or None
"""

Pick one format and apply it consistently across a project. Google style is the most readable for general use.


Practical Tips

Write docstrings while writing the function, not after. If you can’t describe what the function does in one sentence, it might be doing too much.

Don’t repeat the implementation. A docstring that says “loop through items and add to total” adds nothing over reading the code. Explain the contract: what you accept, what you return, what can go wrong.

Keep comments current. An outdated comment is worse than no comment — it actively misleads. When you change code, update the comment.

Use docstrings for public APIs, comments for internal logic. Anything a teammate might call or import deserves a docstring. Internal implementation details are fair game for comments.