Debugging (pdb)
When a program doesn't behave the way you expect, the fastest first move is usually adding a few print() calls to see what values look like at a given point. That works surprisingly often, but it has real limits: you have to guess in advance what to print, you have to edit the code and re-run it for every new guess, and you can't easily inspect state interactively. Python ships with a real interactive debugger, pdb, that lets you pause execution at an exact line and poke around the running program.
print() debugging vs. a real debugger
print() debugging | pdb (real debugger) | |
|---|---|---|
Setup | Edit source, add print calls | Drop in one line, or set a breakpoint |
Iterating on a new question | Edit code again, re-run | Type an expression at the prompt, instantly |
Inspecting arbitrary state | Only what you thought to print | Any variable, any expression, at that exact moment |
Controlling execution | Not possible | Step line-by-line, step into calls, continue, etc. |
Setting a breakpoint
Since Python 3.7, the easiest way to pause execution is the built-in breakpoint() function — no import required. It drops you into the pdb prompt at exactly that line.
def total_price(items):
subtotal = sum(item.price for item in items)
breakpoint() # execution pauses here
tax = subtotal * 0.08
return subtotal + taxOn older codebases, or if you want to be explicit about which debugger module is used, you'll still see the equivalent written out directly:
import pdb
def total_price(items):
subtotal = sum(item.price for item in items)
pdb.set_trace() # equivalent to breakpoint()
tax = subtotal * 0.08
return subtotal + taxWhen execution reaches that line, the program stops and drops you into an interactive (Pdb) prompt right there, with full access to every local variable in scope.
> example.py(4)total_price() -> tax = subtotal * 0.08 (Pdb) p subtotal 129.97 (Pdb)
Essential pdb commands
Once you're at the (Pdb) prompt, a small set of one-letter commands covers almost everything you'll need.
Command | Meaning |
|---|---|
| Run the next line, stepping over any function calls it makes. |
| Run the next line, stepping into a function call if there is one. |
| Resume normal execution until the next breakpoint (or the end). |
| Show the source code around the current line. |
| Evaluate and print any expression — a variable, a function call, anything. |
| Show the current call stack, i.e. how you got here. |
| Set an additional breakpoint at a given line or function. |
| Abort debugging and stop the program entirely. |
(Pdb) l 1 def total_price(items): 2 subtotal = sum(item.price for item in items) 3 breakpoint() 4 -> tax = subtotal * 0.08 5 return subtotal + tax (Pdb) p [item.price for item in items] [49.99, 79.98] (Pdb) n (Pdb) p tax 10.3976 (Pdb) c
You can also run a whole script under the debugger from the start, without editing it:
python -m pdb my_script.py.Inside pdb, any line that isn’t a recognized command is evaluated as plain Python in the current scope — you can even reassign variables to test a fix live.
ccontinues until the next breakpoint or the program ends, so it’s safe to leavebreakpoint()calls in a loop body and step through iterations one at a time.