How to Use pdb in Python for Debugging
A practical guide to using Python's built-in pdb debugger instead of print statements. Learn essential commands, conditional breakpoints, and real-world debugging techniques.
Stop Guessing, Start Debugging: How to Use pdb in Python
Ever spent an hour staring at your Python code, wondering why a variable isn't what you expected? We've all been there. Instead of sprinkling print() statements everywhere like digital breadcrumbs, there's a better way. Let me introduce you to pdb — Python's built-in interactive debugger.
Why pdb beats print statements
Think of print() as checking your reflection in a spoon. It works, but you miss so much. pdb is like having a full-length mirror with zoom capabilities. You can pause execution mid-flow, inspect variables line by line, and even change values while the program runs. PythonSkillset's team uses this daily for everything from simple scripts to complex Django applications.
Getting started: Your first pdb session
The simplest way to use pdb is inserting a breakpoint. Here's how:
def calculate_total(prices):
total = 0
import pdb; pdb.set_trace() # Execution stops here
for price in prices:
total += price
return total
items = [19.99, 5.49, 12.75]
final = calculate_total(items)
print(f"Total: ${final:.2f}")
When you run this script, execution halts right at the pdb.set_trace() line. You'll see a (Pdb) prompt. Now the real fun begins.
Essential pdb commands you'll use every day
Here are the command basics that PythonSkillset's developers rely on:
n(next) — Execute the current line and move to the nextc(continue) — Run until the next breakpoints(step) — Step into a function calll(list) — Show where you are in the codep variable_name— Print the value of a variablepp variable_name— Pretty print for complex objectsq(quit) — Exit the debugger
Real-world example: Debugging a loop
Let's say you're processing customer orders and something's off:
def process_orders(orders):
for index, order in enumerate(orders):
import pdb; pdb.set_trace()
discount = order['total'] * 0.1 if order['loyalty'] else 0
order['final'] = order['total'] - discount
Inside the debugger, you can inspect each order:
(Pdb) p index
0
(Pdb) p order
{'total': 150.00, 'loyalty': True}
(Pdb) p discount
15.0
(Pdb) n
(Pdb) p order['final']
135.0
You see exactly what happens at each iteration. No guessing, no extra print statements cluttering your output.
Advanced tip: Conditional breakpoints
Sometimes you only want to pause when something specific happens. Instead of setting a regular breakpoint, try this:
import pdb
for i in range(100):
result = expensive_calculation(i)
if i == 42:
pdb.set_trace()
Or even better, use Python 3.7+'s built-in breakpoint() function that works the same way but without importing pdb explicitly:
for i in range(100):
if i == 42:
breakpoint() # Same as pdb.set_trace()
When pdb shines brightest
PythonSkillset's debugging toolkit wouldn't be complete without pdb for these scenarios:
- Production-like issues you can't reproduce locally
- Complex data transformations where intermediate states matter
- Multi-threaded code where timing is everything
- API integrations when responses behave unpredictably
A final tip that saves hours
Ever had a bug that only appears on the 50th iteration? Instead of hitting c 49 times, you can write a Python debugger script:
import pdb
class CustomDebugger(pdb.Pdb):
def user_call(self, frame, argument_list):
if frame.f_lineno == target_line:
self.set_continue()
But honestly, most of the time, a simple import pdb; pdb.set_trace() placed strategically will solve 90% of your debugging woes.
Start using pdb today. Your future self — and your teammates — will thank you.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.