C.W.K.
Stream
Lesson 03 of 05 · published

pdb and breakpoint() — Real Debugging

~15 min · pdb, breakpoint, debugger

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

print debugging vs real debugging

Print statements catch the simplest bugs but leave you blind once the problem gets complex. pdb is Python's built-in debugger — drops you into an interactive REPL at any point in your code. You can inspect variables, step through line by line, evaluate expressions in the current scope. The skill payoff is enormous; many developers never learn it and pay for it daily.

breakpoint() — the modern entry

Python 3.7+ has the breakpoint() builtin. Drop it anywhere in your code and execution stops there, dropping into pdb. PYTHONBREAKPOINT=ipdb.set_trace as an env var swaps in the richer ipdb debugger if you've installed it. PYTHONBREAKPOINT=0 disables breakpoints entirely (useful in CI).

The pdb commands you'll actually use

n next line. s step into a function call. c continue (until next breakpoint or end). p expr print an expression. l list source around current line. w show the call stack. u/d move up/down the stack. q quit. The first three are 80% of usage.

post-mortem — debugging an exception

When code crashed, you can debug from the crash point. python -m pdb script.py runs the script under pdb. From inside an interactive session, import pdb; pdb.pm() after an exception drops into the frame where it happened. Variables are still in scope — you can inspect what the function actually saw.

Pythonic Way: When a bug isn't immediately obvious, drop a breakpoint() and look at the actual values. It's faster than adding print statements you'll have to remove. IDE debuggers (VS Code, PyCharm) wrap pdb with a UI; the underlying skill is the same.

Code

breakpoint() — the entry·python
def buggy(items):
    total = 0
    for x in items:
        breakpoint()                   # drops to pdb here
        total += x * 2
    return total

# buggy([1, 2, 3])
# (Pdb) p x          — inspect current x
# 1
# (Pdb) p total
# 0
# (Pdb) n             — next line
# (Pdb) c             — continue to next breakpoint or end
Common pdb commands·python
# Inside pdb prompt:
#
# n          next line (skip into-function calls)
# s          step (into function calls)
# c          continue (until next breakpoint)
# p expr     print expression
# pp expr    pretty-print
# l          list source around current line
# ll         list whole current function
# w          where (show call stack)
# u          up (move up the stack)
# d          down (move down the stack)
# b N        set breakpoint at line N
# b file:N   breakpoint at file:N
# h          help
# h cmd      help on a specific command
# q          quit
post-mortem — drop into the crash site·python
# Run a script that crashes under pdb:
# python -m pdb script.py
# At the prompt, c to start running, you land at the crash

# Inside an interactive session:
import pdb

def bad():
    items = [1, 2, 3]
    return items[10]

try:
    bad()
except IndexError:
    pdb.post_mortem()
# (Pdb) p items
# [1, 2, 3]
# (Pdb) p len(items)
# 3
# Useful in REPL when you want to inspect what the function saw
Conditional breakpoints — without modifying code·python
# At the pdb prompt:
#
# b file.py:42, x > 100
# Sets a breakpoint at line 42 of file.py that fires only when x > 100
#
# Useful for: 'this loop iterates 1 million times,
# stop only when something specific happens'

# Or in code, conditional breakpoint() calls
def process(items):
    for i, x in enumerate(items):
        if x < 0:
            breakpoint()        # only stops on negative
        # process x

External links

Exercise

Write a function find_first_negative(nums) that returns the index of the first negative number, or -1 if none. Deliberately put breakpoint() inside the loop. Run a small script that calls it with [1, 2, -5, 3]. At the pdb prompt, use p i, p x, n to step through, and c to continue. Then disable breakpoints with PYTHONBREAKPOINT=0 env var and confirm the script runs through cleanly.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.