Introduction
A bug is a difference between what the code does and what you meant. Debugging is not guessing: it is a calm, repeatable process.
- Reproduce the bug with a small input.
- Watch the values step by step.
- Guess the cause, then test the guess with a change.
Everyone writes bugs, including experts, and much of a programmer's working day is spent finding them. Doing it with a method, rather than by guessing, is what turns hours of frustration into a few minutes of careful work.
How it works
A bug to find
marks = [70, 80, 90]
total = 0
for i in range(1, len(marks)):
total += marks[i]
print(total / len(marks))The average of 70, 80 and 90 should be 80, but this prints 56.67. Step through and watch i and total: the loop starts at i = 1, so marks[0] (70) is never added, and total ends at 170. range(1, ...) is the bug.
Print debugging
def discount(price, percent):
cut = price * percent / 100
print("debug: cut =", cut)
return price - cut
print(discount(500, 10))When you cannot use a visualizer, a temporary print shows a value at a chosen moment. Label it clearly, and remove it when you are done.
Syntax
print("debug: total =", total) # label temporary prints
assert len(items) > 0 # catch a wrong assumption early
Example
marks = [70, 80, 90]
total = 0
for mark in marks:
total += mark
print(total / len(marks))Looping over the items directly removes the index, and the off-by-one mistake with it. The answer is now 80.0. Often the best fix makes the bug impossible, not just absent.
Line by line
marksholds the three values.total = 0starts the sum.for mark in marks:visits every item, so none can be skipped.total += markadds each one.- Dividing by
len(marks)gives the true average, 80.0.
Expected result
80.0
In the real world
When a website goes wrong, engineers do this same dance on a larger scale: find a small case that fails, watch what really happens, and then change one thing. Rubber duck debugging, which means explaining the code aloud, is a popular and surprisingly effective technique.
Common mistakes
- Changing many things at once. Change one thing, then run again.
- Reading the code you meant to write instead of the code you wrote. Step through it and trust the values you see.
- Ignoring the error message and its line number: it is the best clue you have.
Best practices
- Write down what you expected and what you saw.
- Remove temporary prints when you are done.
- Add a test that would have caught the bug.
Summary
Debugging is a calm process: reproduce the bug, watch the values, make a guess and test it with one change. Prefer a fix that makes the bug impossible, not merely absent.
Practice
Find the bug in def last(items): return items[len(items)] by running it on [1, 2, 3], then fix it.
Quick check
Key takeaways
- Make the bug small and repeatable first.
- Change one thing at a time.
- The best fix makes the bug impossible.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.