The pdb module in the Python standard library is Python's built-in interactive debugger. It lets you pause program execution at any point, inspect variable values, step through code line by line, and evaluate expressions in the current context. Use pdb when print-debugging is not enough and you need to explore program state interactively; pair it with cProfile when the question is about speed rather than correctness.
def calculate(a, b):
result = a * b
breakpoint()
return result + 10
calculate(3, 5)Running this script drops you into an interactive pdb session right at the breakpoint() call, with the program paused mid-execution:
> script.py(4)calculate()
-> return result + 10
(Pdb) p a
3
(Pdb) p b
5
(Pdb) p result
15
(Pdb) cbreakpoint() (built-in since Python 3.7) pauses execution and starts pdb.
p a prints the value of a. p result shows 15 (3 * 5). c continues execution.
Essential pdb commands
Once you are inside a pdb session, these commands cover most debugging needs.
| Command | Short | Description |
|---|---|---|
| next | n | Execute current line, stop at next line in same function |
| step | s | Step into a function call |
| continue | c | Resume execution until next breakpoint |
| print(var) | p var | Print the value of a variable |
| pp var | pp | Pretty-print a variable |
| list | l | Show source code around the current line |
| where | w | Show the call stack |
| up | u | Move up one stack frame |
| down | d | Move down one stack frame |
| args | a | Print arguments of the current function |
| quit | q | Exit the debugger |
Here is a debugging session using several commands:
def divide(a, b):
breakpoint()
return a / b
def main():
result = divide(10, 0)
print(result)
main()Execution pauses at the breakpoint inside divide(), where args and p reveal exactly why the upcoming division is about to fail:
> script.py(3)divide()
-> return a / b
(Pdb) args
a = 10
b = 0
(Pdb) p b
0
(Pdb) n
ZeroDivisionError: division by zero
> script.py(3)divide()
-> return a / b
(Pdb) qargs shows the function parameters. p b confirms b is 0.
n executes the division, which raises ZeroDivisionError. q exits.
Setting breakpoints in pdb
You can set breakpoints while inside a pdb session without editing the source code.
(Pdb) break 12
Breakpoint 1 at script.py:12
(Pdb) break mymodule.my_function
Breakpoint 2 at mymodule.py:5break 12 sets a breakpoint at line 12. break mymodule.my_function sets one directly at a function, wherever it happens to be defined.
Once a breakpoint exists, you can make it conditional, list every breakpoint, and remove one you no longer need:
(Pdb) condition 1 x > 100
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at script.py:12
stop only if x > 100
2 breakpoint keep yes at mymodule.py:5
(Pdb) clear 1
Deleted breakpoint 1condition 1 x > 100 makes breakpoint 1 conditional. break with no arguments lists all breakpoints. clear 1 removes breakpoint 1.
Debugging from the command line
Run a script under pdb from the start:
python -m pdb myscript.pyThis starts pdb before the first line of your script. Use c to run until the first breakpoint() or exception.
For post-mortem debugging after an exception, use:
import pdb
import traceback
import sys
def main():
try:
1 / 0
except Exception:
traceback.print_exc()
pdb.post_mortem(sys.exc_info()[2])pdb.post_mortem() starts the debugger at the point where the exception was raised, letting you inspect the exact state that caused the failure.
Practical example: debugging a recursive function
Step through a recursive function to understand how it works.
def factorial(n):
breakpoint()
if n <= 1:
return 1
return n * factorial(n - 1)
factorial(3)The session below starts by checking n and stepping to the recursive call on the next line of the function:
> script.py(3)factorial()
-> if n <= 1:
(Pdb) p n
3
(Pdb) n
> script.py(5)factorial()
-> return n * factorial(n - 1)From there, s steps into the recursive call itself, descending one level deeper into a fresh call to factorial() with n one less than before:
(Pdb) s
--Call--
> script.py(2)factorial()
-> def factorial(n):
(Pdb) p n
2
(Pdb) n
> script.py(3)factorial()
-> if n <= 1:
(Pdb) p n
2n executes one line. s steps into factorial(n - 1), descending into the recursive call. You can follow the entire call chain and watch n decrease with each recursion level.
Using pdb in production-like environments
Sometimes you cannot add breakpoint() to source code. Start pdb from within a running program:
import pdb
def process(data):
for item in data:
if item.get("error"):
pdb.set_trace()
handle(item)pdb.set_trace() is the older equivalent of breakpoint(). It still works but breakpoint() is preferred in new code because it respects the PYTHONBREAKPOINT environment variable.
Common mistakes
Leaving breakpoint() in production code. breakpoint() halts execution. Remove or guard all breakpoints before deploying. Use PYTHONBREAKPOINT=0 as a failsafe to disable all breakpoints.
Using p for everything instead of pp. p is fine for simple values. For nested dictionaries, lists, or objects, pp (pretty-print) formats the output for readability.
Not using n vs s correctly. n (next) stays in the current function. s (step) enters function calls. If you accidentally step into a standard library function, use r (return) to run until the function returns.
Forgetting that pdb blocks the program. In multi-threaded or async code, breakpoint() freezes only the current thread. Other threads keep running. Use thread-aware debugging tools for concurrent code.
Rune AI
Key Insights
- Add
breakpoint()(Python 3.7+) to pause execution and enter pdb at that line. n(next) executes the current line and stops at the next line in the same function.s(step) steps into function calls;c(continue) runs until the next breakpoint.p variableprints a value;pp variablepretty-prints it.l(list) shows source code around the current line.q(quit) exits the debugger.- Run
python -m pdb script.pyto debug from the start.
Frequently Asked Questions
Should I use pdb or an IDE debugger?
How do I set a breakpoint in my code?
How do I debug an exception after it happens?
Conclusion
pdb is Python's built-in interactive debugger. Use breakpoint() to pause execution at any line, then step through code with n (next), s (step into), and c (continue). Inspect variables with p (print) and pp (pretty-print). For remote debugging or headless servers, pdb is essential. For daily local development, an IDE debugger is more convenient.
More in this topic
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Encode and Decode Base64 Data in Python
Learn how to use Python's base64 module to encode binary data as text and decode Base64 strings back to bytes.