Basic

Prints you can trust

I dropped prints everywhere and the screen became unreadable, so I stopped using them. A few prints with labels, at chosen seams, are a working debugger for most bugs.

What you will see

>>>

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Use labelled prints to find which pass of a loop goes wrong.

1

A loop that should sum 1..5 but skips the last item. Print the running total each pass.

total = 0 for i in range(1, 5): total += i print("total after i=", i, "is", total) print("final:", total)

Before you run it, say out loud what it will print. Then open the answer.

What it prints
total after i= 1 is 1 total after i= 2 is 3 total after i= 3 is 6 total after i= 4 is 10 final: 10
2

The last pass is i=4, but you wanted 1..5. The print shows range stopped one early, which is the bug.

for i in range(1, 6): total += i

Before you run it, say out loud what it will print. Then open the answer.

What it prints
>>>
range(1, 5) stops before 5. The print made that visible instead of leaving you to remember the half-open rule. This is the payoff of printing the loop index.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

You place a few labelled prints at chosen seams, read the bracket they give you, and narrow the bug to the space between them.
1 Pick two or three seams
↓
2 Label each print
↓
3 Read the values in order
↓
4 Bug is between last good and first bad
Why this works
Fewer, labelled prints

Spraying prints makes the log unreadable and you stop trusting it. Instead pick two or three seams, label each print, and read the bracket they give you. Fewer prints give a clearer answer than more prints give noise.

When prints are not enough

For a loop that runs a thousand times, or a value that changes deep in a call tree, prints flood. That is what a real debugger is for. But most bugs are one seam wide, and a labelled print finds those in seconds. Reach for the debugger when the prints stop narrowing.

Examples

Label the print

print("count after loop:", count)

A label makes the value findable in a busy log. An unlabelled number in a wall of output is a needle you cannot find.

Print the type too

print("value:", value, type(value))

When a value looks right but is not, the type is often the bug: a string "5" and a number 5 print almost the same. Printing the type separates them.

Print a counter

for row in rows:
    print("row", i, row)
    i += 1

When a loop misbehaves, print the index and the item each pass. The pass where they stop matching your expectation is the bug.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Debugging from a failure
Previous Lesson
Debugging from a failure
Next Lesson
Stepping with a debugger
Stepping with a debugger →