Historical Context & Motivation
From the very first days of computing, programmers realized that writing code is only half the battle — someone else (or even your future self) has to read that code later. Early programming languages like FORTRAN (1957) allowed programmers to insert comment lines so that human readers could understand what the machine instructions were doing. Without comments, revisiting a program after even a few weeks felt like deciphering a secret language.
As software projects grew from hundreds to millions of lines, the need for structured, machine-readable documentation became urgent. Languages began introducing docstrings — special strings embedded directly in source code that tools could extract automatically. Python, created by Guido van Rossum in 1991, embraced this idea early on, making docstrings a first-class feature of the language. Today, every serious Python project relies on both comments and docstrings to keep code understandable and maintainable.
C character in column 1 to mark a line as a comment, establishing the tradition of inline documentation.# symbol for comments and triple-quoted strings that will later become docstrings.So here is the central question this lesson addresses: how do you write comments and docstrings that are genuinely meaningful — adding clarity without cluttering your code? Let's find out.
Core Principles & Definitions
Before diving into syntax, it helps to understand the two distinct tools Python gives you for documenting code. A comment is a note for humans that Python ignores entirely — it starts with # and extends to the end of the line. A docstring is a special string literal placed as the very first statement inside a module, class, method, or function. Unlike comments, Python actually stores docstrings so that tools and the built-in help() function can access them at runtime.
Comments Explain "Why"
Docstrings Explain "What" & "How"
Don't Repeat the Code
# add 1 to x above x += 1 wastes the reader's time.Keep It Current
Follow PEP 257
Visual Explanation — Anatomy of a Documented Function
The diagram below breaks down a well-documented Python function, labeling every part so you can see exactly where comments and docstrings belong and how they differ in purpose.
Look at how each piece of documentation has a clear job. The green comment at the top gives context about the project (a weather app). The violet docstring follows PEP 257 format: a one-line summary, then sections for Args and Returns. The second green comment clarifies the math formula for anyone skimming the code quickly. Together, they make the function self-explanatory.
How Comments & Docstrings Work Under the Hood
Understanding the difference between comments and docstrings becomes easier when you know what Python actually does with each one. A comment is stripped away by the Python interpreter before any code runs. It is truly invisible to the program. A docstring, on the other hand, is stored as an attribute called __doc__ on the object it belongs to. This means you can access it at runtime, which is what help() and documentation generators rely on.
Comment Syntax
In Python, everything from the # symbol to the end of that line is a comment. Python does not have a built-in multi-line comment syntax like some languages (e.g., /* ... */ in Java). To write multi-line comments, you simply put # at the start of each line.
Docstring Syntax
A docstring uses triple quotes — either """triple double quotes""" or '''triple single quotes'''. By convention, double quotes are preferred. The docstring must be the very first statement inside a function, class, or module for Python to recognize it as the __doc__ attribute. If you place it anywhere else, it is just a regular string that gets ignored.
Accessing Docstrings at Runtime
You can read any object's docstring using print(my_function.__doc__) or by calling help(my_function) in the Python interactive shell. This is incredibly useful — imagine being able to look up a recipe just by asking the oven what it can cook. That is effectively what docstrings give you: built-in, always-available instructions.
__doc__ attribute and can be retrieved with help().Types of Documentation & Style Conventions
Not all comments and docstrings are created equal. Understanding the different types helps you choose the right tool for each situation. Let's classify them and compare the most popular docstring formats.
Types of Comments
| Type | Example | When to Use |
|---|---|---|
| Block comment | # Retry up to 3 times because the API is flaky | Before a block of code to explain a non-obvious decision |
| Inline comment | x = x + 1 # compensate for 0-based index | After a line to clarify a single tricky expression |
| TODO comment | # TODO: add input validation | To mark planned improvements that you haven't implemented yet |
Docstring Formats Compared
Several popular docstring styles exist. The three most common are Google style, NumPy/SciPy style, and reStructuredText (reST) style. Pick one style and use it consistently throughout your project.
| Feature | Google Style | NumPy Style |
|---|---|---|
| Parameters heading | Args: | Parameters
---------- |
| Return heading | Returns: | Returns
------- |
| Readability | Compact and clean — great for short functions | Spacious — ideal for complex scientific functions |
| Common in | General Python, web apps, startups | Data science, machine learning libraries |
Args:, Returns:, and Raises: followed by indented descriptions.Worked Example — Documenting a Student Gradebook Function
Let's walk through the process of writing documentation for a function that calculates a student's letter grade. We will start with undocumented code and transform it step by step into a well-documented piece of software.
def calculate_grade(scores):
avg = sum(scores) / len(scores)
if avg >= 90: return 'A'
elif avg >= 80: return 'B'
elif avg >= 70: return 'C'
elif avg >= 60: return 'D'
else: return 'F'
This works, but anyone reading it has to figure out what scores should be, what the function returns, and what scale it uses."""Calculate a letter grade from a list of numeric scores.""""""Calculate a letter grade from a list of numeric scores.
Args:
scores (list[float]): A list of numeric test scores
(each between 0 and 100).
Returns:
str: A single letter grade ('A', 'B', 'C', 'D', or 'F').
"""# Using standard 10-point grading scale (A=90+, B=80+, etc.)def calculate_grade(scores):
"""Calculate a letter grade from a list of numeric scores.
Args:
scores (list[float]): A list of numeric test scores
(each between 0 and 100).
Returns:
str: A single letter grade ('A', 'B', 'C', 'D', or 'F').
"""
avg = sum(scores) / len(scores)
# Using standard 10-point grading scale (A=90+, B=80+, etc.)
if avg >= 90:
return 'A'
elif avg >= 80:
return 'B'
elif avg >= 70:
return 'C'
elif avg >= 60:
return 'D'
else:
return 'F'help(calculate_grade) and immediately know what it does, what it needs, and what it returns.Good vs. Bad Documentation — Strengths & Pitfalls
Writing documentation is a skill, and like any skill, there are common mistakes. The table below contrasts effective documentation with problematic documentation so you can recognize the difference instantly.
| ❌ Bad Practice | ✅ Good Practice | Why It Matters |
|---|---|---|
# increment x
x += 1 | # Off-by-one fix: API uses 1-based indexing
x += 1 | The bad comment restates the code. The good comment explains the reason. |
def f(a, b):
"""Function.""" | def add_scores(current, new):
"""Add new scores to the current total.""" | Vague names and docstrings force the reader to read every line of code. |
| No docstring at all on a public function | At minimum, a one-line docstring summarizing purpose | Without a docstring, help() returns nothing useful. |
| Outdated comment that contradicts the code | Updated comment that matches current behavior | Misleading docs create bugs and waste debugging time. |
| Commenting every single line | Commenting only where intent is non-obvious | Over-commenting clutters the code and makes real comments hard to spot. |
Connection to Advanced Practices
Once you're comfortable writing comments and docstrings, you'll encounter more advanced documentation practices in professional Python development. These build directly on what you've learned.
| What You Know Now | What Comes Next | How They Connect |
|---|---|---|
| Describing parameter types in docstrings | Type hints — def greet(name: str) -> str: | Type hints formalize what docstrings describe informally, letting tools catch errors automatically. |
| Writing one-line summaries of functions | Sphinx auto-documentation | Sphinx reads your docstrings and generates a full website of documentation — the better your docstrings, the better the website. |
| Using examples in docstrings | Doctests — >>> add(2, 3)
5 | Python's doctest module can run the examples in your docstrings as actual tests, ensuring your docs stay accurate. |
| Commenting "why" for tricky code | Architecture Decision Records (ADRs) | In large projects, teams write formal documents explaining major design decisions — like comments, but at a project level. |
As you move into AP Computer Science, college courses, or open-source projects, these advanced techniques will feel like natural extensions of the habits you're building now. Every professional Python developer writes docstrings — the skill you're learning today is one you'll use for the rest of your programming career.
Practice Problems
def area_of_circle(radius):
return 3.14159 * radius ** 2# This function adds two numbers
def calculate_bmi(weight_kg, height_m):
# calculate bmi
bmi = weight_kg / (height_m ** 2)
# WHO classifies BMI >= 30 as obese
if bmi >= 30:
return 'obese'
return 'not obese'is_overdue that takes a due_date (string in 'YYYY-MM-DD' format) and returns True if today's date is past the due date. Include a docstring with Args, Returns, and an Example section, plus at least one meaningful comment in the code body.Lesson Summary
Python gives you two tools for documentation: comments (lines starting with #) and docstrings (triple-quoted strings placed as the first statement in a function, class, or module). Comments are discarded by the interpreter and exist only in source code, while docstrings are stored at runtime as the __doc__ attribute and accessible via help(). Comments should explain why code works a certain way, while docstrings describe what a function does and how to use it.
Follow PEP 257 conventions and choose a consistent style like Google style with Args: and Returns: sections. Avoid the three big pitfalls: restating obvious code, leaving docs outdated, and over-commenting every line. As you advance, docstrings connect directly to type hints, auto-documentation tools, and doctests — making today's habit one of the most valuable skills in professional Python development.