Lesson 12.3: Debugging Strategies
What you will learn:
- How to read and interpret error messages effectively
- Using print statements to find bugs
- Commenting out code to isolate problems
- Common beginner mistakes and how to avoid them
- The rubber duck debugging technique
1. Reading Error Messages Carefully
The most important debugging skill is learning to read error messages. They usually tell you exactly what went wrong.
- Look at the last line - it tells you the error type and message
- Look at the line number - it tells you where the error occurred
- Look at the code shown - it shows the exact line that failed
- Read upward for the chain of calls that led to the error
Reading a Traceback
# This error message: # Traceback (most recent call last): # File "app.py", line 5, in calculate # return total / count # ZeroDivisionError: division by zero # Tells you: # 1. Error type: ZeroDivisionError # 2. File: app.py, line 5 # 3. The problematic code: total / count # 4. "count" must be 0
2. Print Debugging
The simplest and most effective debugging technique is adding print() statements to see what your program is actually doing:
Before Debugging (Bug)
def calculate_average(grades): total = 0 for grade in grades: total = grade # Bug! Should be total += grade return total / len(grades) result = calculate_average([80, 90, 100]) print(result) # Expected: 90.0, Got: 33.33...
With Print Debugging
def calculate_average(grades): total = 0 for grade in grades: total = grade print(f"DEBUG: grade={grade}, total={total}") # Add this print(f"DEBUG: final total={total}") # And this return total / len(grades) result = calculate_average([80, 90, 100])
DEBUG: grade=90, total=90
DEBUG: grade=100, total=100
DEBUG: final total=100
The debug output reveals the bug: total is being replaced instead of accumulated. Changing total = grade to total += grade fixes it.
print(f"DEBUG [{variable_name}]: {variable}") for clarity.
3. Using Comments to Isolate Problems
If you are not sure which part of your code is causing the problem, comment out sections to narrow it down:
Isolating a Bug
# Something is wrong with this program # Comment out sections one at a time to find the bug data = load_data() # Step 1: Does this work? # cleaned = clean_data(data) # Step 2: Comment this out # results = process(cleaned) # Step 3: And this # save_results(results) # Step 4: And this # If Step 1 works alone, uncomment Step 2 # If Step 1+2 work, uncomment Step 3 # Keep going until you find the step that breaks
This technique is called binary search debugging - you systematically narrow down where the problem is by testing half the code at a time.
4. Common Beginner Mistakes
Mistake 1: Using = Instead of ==
# Wrong: assignment instead of comparison # if x = 5: # SyntaxError! # Right: use == for comparison if x == 5: print("x is five")
Mistake 2: Modifying a List While Looping
# Wrong: removing items while iterating numbers = [1, 2, 3, 4, 5] for n in numbers: if n % 2 == 0: numbers.remove(n) # Causes skipped items! # Right: create a new list numbers = [1, 2, 3, 4, 5] odds = [n for n in numbers if n % 2 != 0]
Mistake 3: Indentation Errors
# Wrong: code is inside the loop but shouldn't be total = 0 for i in range(5): total += i print(f"Total: {total}") # Prints 5 times! # Right: move print outside the loop total = 0 for i in range(5): total += i print(f"Total: {total}") # Prints once
Mistake 4: Off-by-One Errors
# Wrong: range(5) gives 0,1,2,3,4 (not 1-5) for i in range(5): print(i) # 0, 1, 2, 3, 4 # Right: range(1, 6) gives 1,2,3,4,5 for i in range(1, 6): print(i) # 1, 2, 3, 4, 5
5. Rubber Duck Debugging
Rubber duck debugging is a surprisingly effective technique. The idea is simple: explain your code out loud, line by line, to a rubber duck (or any object). The act of explaining often reveals the bug.
- Place a rubber duck (or any object) on your desk
- Explain to the duck what your code is supposed to do
- Go through your code line by line, explaining each line
- At some point, you will say what the code does versus what it should do, and realize the bug
This works because explaining forces you to slow down and think carefully about each step. Many bugs are caused by assumptions that we do not question until we try to explain them.
Debugging Checklist
- Read the error message carefully (bottom up)
- Check the line number mentioned in the error
- Add print statements to trace your variables
- Comment out code to isolate the problem
- Check for common mistakes (=, indentation, off-by-one)
- Explain your code to a rubber duck
- Take a break and come back with fresh eyes
Check Your Understanding
Your code produces wrong results but no error message. What should you do first?
Add print() statements at key points in your code to check what values your variables actually hold. This helps you find where the program's behavior diverges from what you expected. Start by printing variables right before the output that is wrong, then work backward.
Key Takeaways
- Read error messages from the bottom up - the last line has the error type
- Use
print()statements to trace variable values - Comment out code sections to isolate the problem
- Watch for common mistakes:
=vs==, indentation, off-by-one errors - Explain your code out loud (rubber duck debugging) to find logic errors
- Taking a break is a valid debugging strategy