SECTION 1
Historical Context & Motivation
Have you ever opened up old code you wrote a few months ago and thought, "What was I trying to do here?" You are not alone. Since the earliest days of programming, developers have struggled with the challenge of making code understandable to other people — and to their future selves. Documentation is the practice of explaining what your code does, and Python has always treated readability as a first-class priority.
Python's creator, Guido van Rossum, famously said, "Code is read much more often than it is written." That philosophy led to two powerful features built right into the language: docstrings for human-readable documentation and type hints for signaling what kinds of data a function expects and returns.
1991 • Python 0.9 Released
2001 • PEP 257 — Docstring Conventions
2006 • PEP 3107 — Function Annotations
2014 • PEP 484 — Type Hints
2022+ • Modern Python
The central question these features address is simple: How can we write code that clearly communicates its purpose, inputs, and outputs — without forcing someone to read every line? Docstrings and type hints are Python's answer to that challenge.
SECTION 2
Core Principles & Definitions
Before diving into code, let's define the two key ideas. A docstring is a special string placed at the very beginning of a function (or class, or module) that describes what it does. It is enclosed in triple quotes ("""...""") and is stored by Python so that other tools can access it. A type hint is an annotation you add to a function's parameters and return value to indicate the expected data types, like int, str, or float.
Docstrings Explain "What"
Type Hints Explain "What Kind"
Both Are Optional (but Recommended)
Tools Read Them Automatically
help() function can display docstrings and type hints as pop-up tooltips while you code.KEY TAKEAWAY
SECTION 3
Visual Explanation — Anatomy of a Documented Function
The diagram below shows a single Python function with every documentation feature labeled. Study how the type hints sit inside the function signature (the def line), while the docstring appears as the first line inside the function body.
Notice how each piece of documentation occupies a specific location. The type hints are part of the def line itself — they sit right next to the parameter names and before the colon that ends the signature. The docstring, on the other hand, is a regular Python string that happens to be the very first statement inside the function. Python stores it in a special attribute called __doc__, which means you can retrieve it at any time by calling help(calculate_area) in the interactive console.
SECTION 4
How Docstrings and Type Hints Work Under the Hood
Docstring Mechanics
When Python encounters a string literal as the first statement of a function, class, or module, it does not throw it away. Instead, it stores that string in the object's __doc__ attribute. This is not a comment — it is live data that programs, libraries, and editors can access. For example, if you type print(calculate_area.__doc__), Python will print the docstring you wrote.
Comments vs. Docstrings
#) is completely ignored by Python at runtime — it vanishes. A docstring is preserved and becomes part of the function object. Always use a docstring to describe a function's purpose, and use comments for inline notes about tricky logic.Type Hint Mechanics
Type hints use a colon (:) after a parameter name and an arrow (->) before the final colon of the def line to annotate types. The general pattern is:
TYPE HINT SYNTAX
param₁, param₂ = parameter names; Type₁, Type₂ = expected input types (e.g., int, str); ReturnType = the type of the value the function returns.
Here is the crucial detail: Python does not enforce type hints at runtime. If your hint says x: int but you pass a string, Python will not stop you. Type hints are for humans and tools. External programs like mypy or your code editor can read the hints and warn you about mismatches before you run the program. Think of them as helpful road signs — they guide you, but they do not build physical barriers.
Common Built-in Types for Hints
| Type | Meaning | Example Value |
|---|---|---|
int | Whole number | 42 |
float | Decimal number | 3.14 |
str | Text string | "hello" |
bool | True or False | True |
list | Ordered collection | [1, 2, 3] |
None | No return value | (used in return type) |
The most common types you will use in high school Python projects.
SECTION 5
Docstring Styles & Multi-Line Format
Docstrings come in two flavors: one-line and multi-line. A one-line docstring fits on a single line and is perfect for simple functions. A multi-line docstring is used when you need to describe parameters, return values, or special behavior in more detail. The most popular multi-line format for beginners is the Google style, which organizes information under headings like Args and Returns.
In the multi-line example, notice the structure: the first line is a brief summary, then a blank line, then the Args: section lists each parameter with an explanation, and the Returns: section describes what the function gives back. This consistent structure lets tools like Sphinx automatically generate beautiful HTML documentation for entire projects.
Pro Tip
""" right after the def line and press Enter. If you have the Python Docstring Generator extension installed, it will automatically scaffold a multi-line docstring template with all your parameters pre-filled!SECTION 6
Worked Example — Documenting a Function Step by Step
Let's walk through the process of taking an undocumented function and adding docstrings and type hints. We will use a function that converts a temperature from Fahrenheit to Celsius.
Adding Documentation to a Temperature Converter
- 1
Step 1 — Start with the bare function
Here is the original, undocumented function:def to_celsius(f): return (f - 32) * 5 / 9This works, but a reader has to figure out whatfmeans and what the function returns. - 2
Step 2 — Add type hints to parameters and return value
We know the input is a number (a float for decimal temperatures) and the output is also a float. We annotate both:def to_celsius(fahrenheit: float) -> float:Notice we also renamedftofahrenheitfor clarity — good naming works hand-in-hand with documentation.Parameter hint:fahrenheit: float· Return hint:-> float - 3
Step 3 — Write a one-line docstring
Since this function is straightforward, a one-line docstring is sufficient. Place it as the first statement inside the function body:def to_celsius(fahrenheit: float) -> float: """Convert a temperature from Fahrenheit to Celsius.""" return (fahrenheit - 32) * 5 / 9Docstring:"""Convert a temperature from Fahrenheit to Celsius.""" - 4
Step 4 — Verify with help()
In the Python console, callhelp(to_celsius). Python will display:Help on function to_celsius: to_celsius(fahrenheit: float) -> float Convert a temperature from Fahrenheit to Celsius.Both the type hints and the docstring appear automatically! - 5
Step 5 — Expand to multi-line (optional upgrade)
If we wanted to add more detail, we could expand to the Google style:def to_celsius(fahrenheit: float) -> float: """Convert a temperature from Fahrenheit to Celsius. Args: fahrenheit: Temperature in degrees Fahrenheit. Returns: Temperature converted to degrees Celsius. """ return (fahrenheit - 32) * 5 / 9Fully documented function with type hints and a Google-style multi-line docstring.
SECTION 7
Documented vs. Undocumented Code
To really appreciate the value of docstrings and type hints, let's compare two versions of the same function and see how each one reads to a new developer encountering the code for the first time.
| Aspect | Undocumented Version | Documented Version |
|---|---|---|
| Function signature | def calc(a, b): | def calc_bmi(weight_kg: float, height_m: float) -> float: |
| Purpose clear? | No — "calc" could mean anything | Yes — the name and hints tell you it calculates BMI |
| Parameter meaning | Unknown — what are a and b? | Clear — weight in kg, height in meters |
| Return type | Must read the code to guess | Clearly a float |
| Editor support | Minimal autocomplete | Rich tooltips and error detection |
| Bug risk | Higher — someone might pass strings | Lower — the editor flags type mismatches |
Side-by-side comparison of undocumented vs. documented function approaches.
KEY TAKEAWAY
SECTION 8
Connection to Advanced Python Tooling
Docstrings and type hints are your entry point into a much larger ecosystem of professional Python tools. As you advance, these features become even more powerful. Here is a preview of where they lead.
| What You Learn Now | What It Unlocks Later |
|---|---|
| Basic type hints (int, str, float) | Advanced types like list[int], dict[str, float], Optional[str], and generics |
| One-line docstrings | Auto-generated documentation websites using Sphinx or MkDocs |
| Descriptive parameter names | API design where parameter names become part of public interfaces |
| Editor tooltips from type hints | Static analysis with mypy that catches type errors across entire codebases |
| Google-style docstrings | Doctest — embedding runnable test cases inside your docstrings |
How today's basics scale into professional development workflows.
In college-level courses and industry jobs, you will encounter tools like mypy (a static type checker that reads your hints and flags bugs), Sphinx (which turns docstrings into full documentation websites), and Pydantic (which uses type hints to validate data at runtime). Every one of these tools builds on the exact skills you are learning today. Investing time in clean documentation now will pay dividends for years.
Looking Ahead
| operator instead of Union for combined types. For example, def process(data: int | str) -> str: means the parameter can be either an int or a str. The syntax keeps getting simpler!SECTION 9
Practice Problems
Question 1: CONCEPTUAL
#) and a docstring in Python. Why would you choose a docstring over a comment to describe a function?Show answer
# and is completely ignored by Python at runtime — it is invisible to the program. A docstring, on the other hand, is a triple-quoted string placed as the first statement in a function body, and Python stores it in the function's __doc__ attribute. This means that tools like help() and code editors can read and display docstrings. You should use a docstring to describe a function's overall purpose because it is accessible programmatically, whereas a comment is better suited for explaining a tricky line of code within the body.Question 2: BASIC CALCULATION
def greet_student(name, score):
return f"{name}, you scored {score} points!"Show answer
def greet_student(name: str, score: int) -> str:. The parameter name is annotated as str because it holds text, score is annotated as int because scores are whole numbers, and the return type is str because the f-string produces a text string.Question 3: INTERMEDIATE
average that takes a list of floats and returns their average as a float. Include type hints for the parameter and return value, and write a multi-line Google-style docstring with Args and Returns sections.Show answer
def average(numbers: list) -> float:
"""Calculate the arithmetic average of a list of numbers.
Args:
numbers: A list of float values to average.
Returns:
The arithmetic mean of the input values.
"""
return sum(numbers) / len(numbers)
The function signature uses list as the parameter type and float as the return type. The docstring opens with a summary sentence, then has an Args section describing the input and a Returns section describing the output. Note that in more advanced Python, you might write list[float] to be more specific about the list contents.Question 4: APPLIED
is_passing that takes a student's score (float) and an optional passing threshold (float, defaulting to 60.0), and returns True if the student passed and False otherwise. Include type hints and a Google-style docstring.Show answer
def is_passing(score: float, threshold: float = 60.0) -> bool:
"""Determine whether a student's score meets the passing threshold.
Args:
score: The student's numeric score.
threshold: The minimum score required to pass.
Defaults to 60.0.
Returns:
True if score is greater than or equal to threshold,
False otherwise.
"""
return score >= threshold
Notice how the default value = 60.0 appears after the type hint. The docstring also mentions the default value under the threshold parameter. The return type is bool because the function returns True or False.Question 5: CRITICAL THINKING
Show answer
def area(radius: float) -> float:, you immediately know what types are expected without reading the function body. Second, code editors like VS Code and PyCharm use type hints to provide intelligent autocomplete and to highlight type mismatches with red underlines before you even run the program, catching bugs earlier in the development process. Third, static analysis tools like mypy can scan an entire codebase for type inconsistencies, functioning as an automated code reviewer. In professional settings, these benefits compound: on a team of ten developers, clear type hints prevent miscommunication and reduce debugging time significantly. The argument that they are "pointless" overlooks the fact that code is read far more often than it is written, and type hints make that reading dramatically faster.SUMMARY
Lesson Summary
Summary
In this lesson, you learned two essential tools for writing readable Python code. Docstrings are triple-quoted strings placed as the first statement inside a function that describe its purpose, parameters, and return value. They are stored in the __doc__ attribute and can be accessed via help(). Type hints annotate the expected types of function parameters (using : type) and return values (using -> type). Although Python does not enforce type hints at runtime, they enable editor autocompletion, static type checking, and dramatically improved code readability.
You explored two docstring styles: one-line for simple functions and Google-style multi-line docstrings with Args and Returns sections for more complex functions. These skills form the foundation for professional documentation practices, auto-generated docs with Sphinx, and static analysis with tools like mypy. Remember: good documentation is a gift to your future self and to anyone who reads your code.