Learn Without Walls
← Previous Lesson Lesson 3 of 4 Next Lesson →

Lesson 12.3: Debugging Strategies

What you will learn:

1. Reading Error Messages Carefully

The most important debugging skill is learning to read error messages. They usually tell you exactly what went wrong.

Steps to read an error:
  1. Look at the last line - it tells you the error type and message
  2. Look at the line number - it tells you where the error occurred
  3. Look at the code shown - it shows the exact line that failed
  4. 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=80, total=80
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.

Tip: Prefix debug prints with "DEBUG:" so you can easily find and remove them later. Some programmers also use 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.

How it works:
  1. Place a rubber duck (or any object) on your desk
  2. Explain to the duck what your code is supposed to do
  3. Go through your code line by line, explaining each line
  4. 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

  1. Read the error message carefully (bottom up)
  2. Check the line number mentioned in the error
  3. Add print statements to trace your variables
  4. Comment out code to isolate the problem
  5. Check for common mistakes (=, indentation, off-by-one)
  6. Explain your code to a rubber duck
  7. 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

← Previous Lesson Lesson 3 of 4 Next Lesson →