Python Comments and Docstrings
Comments should explain a decision that code alone cannot make: why a boundary exists, why a fallback is safe, or why a surprising rule is required. Do not narrate obvious syntax. Use docstrings for a function or module's public contract, and keep both comments and documentation accurate as behavior changes.
Work through the examples in order. Each one has a small, runnable program, a visible output, and one deliberate change to make. Keep the data rule separate from printing or external work so you can explain and test the behavior at every step.
What You Will Build
This page is a focused Python code lab. The sequence starts with a small working form, then adds one rule, one boundary, or one reusable function at a time. Use a local interpreter while reading; an example is complete only after you run it and predict the changed-input result.
Good Python code makes data ownership and failure behavior visible. Validate external input near the boundary, avoid printing private values, and let a caller choose how to present or persist a calculated result.
Example 1: Use a comment for a business reason
The comment explains why the lower bound exists. Repeating that a comparison happens would add noise; naming the decision gives future readers useful context.
Python
minimum_age = 18
# The policy requires adult account holders.
if minimum_age >= 18:
print("adult account policy")
Expected Result
adult account policy
Try next: Do not comment that if checks a condition; that is already clear from the code.
Trace the program from its input through the printed result. Change one value before moving forward, then explain why the result changed. That is how short examples become reliable habits rather than copied syntax.
Example 2: Document a public function
A docstring states the contract near the function it describes. Keep it focused on inputs, returned behavior, and important failure cases.
Python
def normalize_name(value: str) -> str:
"""Return a trimmed title-cased name; reject blank input."""
cleaned = " ".join(value.split())
if not cleaned:
raise ValueError("name is required")
return cleaned.title()
print(normalize_name(" farhad dubey "))
Expected Result
Farhad Dubey
Try next: Read normalize_name.__doc__ in a REPL and keep that sentence correct if you change the validation rule.
Trace the program from its input through the printed result. Change one value before moving forward, then explain why the result changed. That is how short examples become reliable habits rather than copied syntax.
Example 3: Explain a non-obvious boundary
The code performs the calculation, while the comment records why the cap is part of the product rule. This protects the intent during later refactoring.
Python
def reward_points(amount: int) -> int:
points = amount // 100
# A daily cap prevents one large order from consuming the full budget.
return min(points, 50)
print(reward_points(8000))
Expected Result
50
Try next: Try 4900 and verify that values below the cap are not changed.
Trace the program from its input through the printed result. Change one value before moving forward, then explain why the result changed. That is how short examples become reliable habits rather than copied syntax.
Example 4: Keep a TODO actionable
A TODO should identify a concrete missing decision or test, not become a permanent substitute for design work. Keep it near the code it affects.
Python
def delivery_label(days: int) -> str:
# TODO: replace this fixed threshold after delivery data is measured.
if days <= 2:
return "fast"
return "standard"
print(delivery_label(2))
Expected Result
fast
Try next: When the data exists, replace the TODO with the measured rule rather than adding another comment.
Trace the program from its input through the printed result. Change one value before moving forward, then explain why the result changed. That is how short examples become reliable habits rather than copied syntax.
Example 5: Do not use comments to hide unsafe output
A comment cannot make logging private data safe. Print only the information a learning example or operator needs, while keeping secrets out of both output and comments.
Python
def connection_label(host: str) -> str:
return f"connecting to {host}"
print(connection_label("database.internal"))
Expected Result
connecting to database.internal
Try next: Never add a password, token, or full session value to this output just to make debugging easier.
Trace the program from its input through the printed result. Change one value before moving forward, then explain why the result changed. That is how short examples become reliable habits rather than copied syntax.
Example 6: Make the input visible
Start by naming the value the next line depends on. This keeps the lesson input explicit before we apply a transformation or call an external boundary. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
lesson = "Python Comments and Docstrings"
print(lesson.upper())Expected Result
PYTHON COMMENTS AND DOCSTRINGS
Try next: Replace the sample value with one from your own notes, predict the result, and then run it.
Example 7: Guard an empty boundary
A small guard makes the allowed and rejected path visible. We want a caller to receive an intentional result instead of discovering an unexplained failure later. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
def accepted(value: str) -> bool:
return bool(value.strip())
print(accepted("Python Comments and Docstrings"))Expected Result
True
Try next: Try an empty value as well as the normal value and describe why the two outcomes differ.
Example 8: Keep the transformation pure
This step returns a value instead of mixing the rule with display or storage work. That separation gives us a small unit we can run, test, and reuse. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
def double(value: int) -> int:
return value * 2
print(double(6))Expected Result
12
Try next: Call the same rule twice with different inputs and confirm that each result depends only on its input.
Example 9: Make a branch deliberate
Use a named branch where the business rule changes. A future reader should be able to point at the condition and state the result for both sides. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
score = 7
result = "ready" if score >= 5 else "review"
print(result)Expected Result
ready
Try next: Change the boundary value by one and explain exactly which branch becomes active.
Example 10: Use a collection without hidden mutation
Collections become safer when we can see which value is read, which value is derived, and whether the original collection remains owned by the caller. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
lessons = ["Python Comments and Docstrings", "boundary"]
print(" | ".join(lessons))Expected Result
Python Comments and Docstrings | boundary
Try next: Add one more item and predict the derived result before executing the code.
Example 11: Return a named outcome
A named outcome is easier to test than an implied side effect. We can now distinguish a successful path from a rejected path without guessing from console noise. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
outcome = {"status": "ready", "lesson": "Python Comments and Docstrings"}
print(outcome["status"])Expected Result
ready
Try next: Rename the outcome in your own words while preserving the same success and failure rule.
Example 12: Trace a small loop
Work through one value at a time. The point is not to memorize syntax; it is to see how the accumulator or output changes after each repeatable step. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
total = 0
for value in [1, 2, 3]:
total += value
print(total)Expected Result
6
Try next: Use a shorter collection first, then add one value and trace the extra iteration aloud.
Example 13: Keep display at the edge
The core rule prepares a value, while the outer line decides how to show it. That keeps the result usable by a UI, test, API, or command-line caller. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
def display(value: str) -> str:
return f"Lesson: {value}"
print(display("Python Comments and Docstrings"))Expected Result
Lesson: Python Comments and Docstrings
Try next: Change only the display text and verify that the underlying rule and result stay unchanged.
Example 14: Test the closest boundary
A useful example includes the nearest boundary, not only the happy path. We are making the behavior inspectable before a real caller relies on it. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
def quantity(value: int) -> int:
if value < 1:
raise ValueError("quantity must be positive")
return value
print(quantity(1))Expected Result
1
Try next: Try the lowest supported value and then one value just outside the accepted range.
Example 15: Write a tiny regression check
A compact assertion turns the lesson into a repeatable promise. It helps us catch a changed rule before a larger program hides the source of the mistake. We are applying that habit while revisiting Python Comments and Docstrings.
Keep the example small enough to trace. First predict the normal result; then change one input and explain the boundary result in your own words.
Python
result = "Python Comments and Docstrings".upper()
assert result == "PYTHON COMMENTS AND DOCSTRINGS"
print("contract holds")Expected Result
contract holds
Try next: Deliberately change the expected value once, observe the failed check, and then restore the correct contract.
Practice Checklist
Do not advance after only reading the output. Rebuild the five examples, change one input in each, and write one small version using your own names and values.
- Practice 1: recreate “Use a comment for a business reason”, make the suggested change, and state the expected result before running it.
- Practice 2: recreate “Document a public function”, make the suggested change, and state the expected result before running it.
- Practice 3: recreate “Explain a non-obvious boundary”, make the suggested change, and state the expected result before running it.
- Practice 4: recreate “Keep a TODO actionable”, make the suggested change, and state the expected result before running it.
- Practice 5: recreate “Do not use comments to hide unsafe output”, make the suggested change, and state the expected result before running it.
For a stronger check, identify one invalid input and state exactly what a caller should observe. A generic crash, silent fallback, or hidden side effect is not a complete program contract.
Common Mistakes
- Copying a short program without changing an input and therefore never checking whether its rule was understood.
- Using a compact expression where a branch, validation check, or loop would communicate the real behavior more clearly.
- Using print as the only result of reusable logic instead of returning a value a caller can test or display.
- Putting secrets, full request bodies, or private state into output while debugging.
