Meet `breakpoint()`: Your Built‑In Debug Superpower in Modern Python
Since Python 3.7 the humble breakpoint()
call is baked right into the language, giving you an instant entry point to the debugger—without needing import pdb; pdb.set_trace()
scattered everywhere. It’s the quickest way to pause execution, poke around, and resume as if nothing happened.
def weird_math(x):
result = (x ** 2) // 3
breakpoint() # ↓ the program halts here
return result + 42
Run the script and Python drops you into the familiar pdb prompt at that line. Now you can inspect locals (p locals()
), change variables (x = 99
), step (n
/ s
) or continue (c
).
Tip: You can sprinkle
breakpoint()
freely in exploratory code and remove it later without cleanup imports.
pdb
/ ipdb
Command Cheat‑SheetBelow is a compact but thorough reference you can paste straight into your blog after the “Power tricks” section.
Command | Long form | What it does | Handy micro‑example |
---|---|---|---|
n | next | Execute next line in current frame (skips over function bodies). | Step through a for loop without diving into len() |
s | step | Step into the next function call. | Dive inside calculate() to see why it returns None |
c | continue | Resume execution until next breakpoint (or program end). | Exit the debugger after a quick variable check |
l | list | Show source around current line. Add a line number → l 120 . | “Where am I exactly?” |
ll | — | List entire current function. | Scroll the whole context of a 50‑line handler |
p expr | print expr | Evaluate & print an expression. | p len(data) |
pp expr | prettyprint expr | Pretty‑print objects via pprint.pformat . | pp settings |
! stmt | — | Run an arbitrary Python statement. | ! filtered = [x*2 for x in data] |
b line | break line | Set breakpoint in current file. | b 210 |
b file:line | — | Breakpoint in another file. | b utils.py:45 |
b func | — | Breakpoint at function entry. | b DataLoader.load |
b | — | List all breakpoints & numbers. | Quick overview |
cl num | clear num | Remove breakpoint num. | cl 3 |
disable num / enable num | — | Toggle breakpoint without deleting. | Temporarily skip an expensive stop |
tbreak line | — | One‑shot breakpoint; auto‑clears after hit. | Pause only the first time a loop runs |
u | up | Move up one frame (caller). | Inspect arguments in the caller stack |
d | down | Move down one frame (callee). | Return to the frame you stepped into |
args | — | Print function arguments of current frame. | args inside def foo(a, b=3) |
where / w | — | Full stack trace (current line marked with →). | Snapshot of call chain |
bt | backtrace | Alias of where . | |
retval | — | Show value returned by last return when stepping. | See what parse() produced |
q | quit | Abort debug session & terminate program. | Emergency exit |
jump line | j line | Move execution cursor to line (same file). Dangerous but powerful. | Skip a branch: jump 180 |
run args | — | Restart program with given args. | run --fast 500 in a CLI script |
debug expr | — | Evaluate expression in its own mini‑debugger. | debug some_generator() |
help | help topic | Built‑in help (help break , help list , …). | Discover subtle flags |
Tip: Prefix any command with a repeat count:
10 n
skips ten lines;2 u
climbs two frames.
breakpoint()
simply calls sys.breakpointhook()
, whose default implementation launches pdb
. That means you can:
Disable all breakpoints dynamically:
export PYTHONBREAKPOINT=0 # in POSIX shells
set PYTHONBREAKPOINT=0 # Windows cmd
Every breakpoint()
becomes a no‑op—handy in CI pipelines.
Swap in another debugger (e.g. ipdb
, pudb
, web-pdb
):
export PYTHONBREAKPOINT=ipdb.set_trace
Now the same line of code opens whichever debugger you prefer, without touching source files.
Provide a custom hook at runtime:
import sys, logging
def log_only(*args, **kwargs):
logging.warning("breakpoint() hit!")
sys.breakpointhook = log_only
Goal | Quick recipe |
---|---|
Jump in only when a condition explodes | if total < 0: breakpoint() |
Drop into a debugger inside a list‑comprehension | Use lambda : [f(x) if x>0 else (lambda: (breakpoint(), None)[1])() for x in data] |
Remote debugging in a container | export PYTHONBREAKPOINT=remote_pdb.set_trace + start remote‑pdb server |
Step through async code smoothly | Combine with python -m pdb -m your_script or use ipdb which understands coroutines better |