Of course! ipdb is an excellent, interactive debugger for Python. It's a drop-in replacement for the standard pdb but with many quality-of-life improvements, like syntax highlighting and tab completion.

Here’s a comprehensive guide on how to use ipdb for debugging in Python.
What is ipdb and Why Use It?
ipdb is an advanced Python debugger, a fork of the standard `pdb module. It provides an interactive command-line interface to inspect your code while it's running. This allows you to:
- Pause execution at any point.
- Inspect variables and their values.
- Step through code line by line.
- See the call stack to understand how you got to the current line.
- Change variable values on the fly to test scenarios.
It's far more powerful than adding print() statements everywhere.
Key Advantages over pdb:

- Tab Completion: Autocomplete for commands, variables, and methods.
- Syntax Highlighting: Code is easier to read.
- Better Command Shortcuts:
llfor long list of code,pfor print. - Better Usability: Generally more pleasant to work with.
Installation
First, you need to install it. It's available via pip.
pip install ipdb
How to Use ipdb
There are three primary ways to start the debugger:
- Dropping into the Debugger on Exception: The most common and useful method.
- Setting a Break Programmatically: Inserting a
breakpoint()call in your code. - Running from the Command Line: Debugging a script from the start.
Method 1: On Exception (The "Magic" Way)
This is the easiest way to start debugging. When your script crashes with an exception, ipdb will automatically launch, pausing execution right at the line where the error occurred.
Step 1: Set an Environment Variable
In your terminal, before running your Python script, set the PYTHONBREAKPOINT environment variable to 0. This tells Python to use ipdb as the default debugger when breakpoint() is called (which happens automatically on uncaught exceptions).
# For Linux/macOS export PYTHONBREAKPOINT=0 # For Windows (Command Prompt) set PYTHONBREAKPOINT=0 # For Windows (PowerShell) $env:PYTHONBREAKPOINT=0
Step 2: Write Your Code
Let's create a script named buggy_script.py with an intentional error.
# buggy_script.py
def process_data(data):
"""Processes a list of numbers."""
print("Starting processing...")
result = []
for item in data:
# Let's pretend we found a bug here
processed_item = item * 2 # This will fail if item is a string
result.append(processed_item)
return result
if __name__ == "__main__":
my_data = [1, 2, 3, 'four', 5]
final_result = process_data(my_data)
print(f"Final result: {final_result}")
Step 3: Run the Script
Now, run the script from your terminal. It will hit the TypeError when it tries to multiply the string 'four' by 2. ipdb will automatically activate.
python buggy_script.py
Output:
Starting processing...
Traceback (most recent call last):
File "buggy_script.py", line 12, in <module>
final_result = process_data(my_data)
File "buggy_script.py", line 7, in process_data
processed_item = item * 2
TypeError: can't multiply sequence by non-int of type 'int'
> /path/to/your/project/buggy_script.py(7)process_data()
-> processed_item = item * 2
(Pdb)
You are now in the ipdb prompt! The arrow -> points to the line that caused the error.
Method 2: Programmatically with breakpoint()
You can insert breakpoint() directly into your code wherever you want to pause execution and inspect the state.
Modify buggy_script.py:
# buggy_script.py
def process_data(data):
"""Processes a list of numbers."""
print("Starting processing...")
result = []
for item in data:
# Let's inspect the 'item' variable right here
breakpoint() # <--- Add this line
processed_item = item * 2
result.append(processed_item)
return result
if __name__ == "__main__":
my_data = [1, 2, 3, 'four', 5]
final_result = process_data(my_data)
print(f"Final result: {final_result}")
Now, run the script again. It will pause at the breakpoint() call, before the error occurs.
python buggy_script.py
Output:
Starting processing...
> /path/to/your/project/buggy_script.py(7)process_data()
-> breakpoint()
(Pdb)
Essential ipdb Commands
Once you're at the (Pdb) prompt, you can use various commands. You can often use short forms (e.g., n for next).
| Command | Short | Description | Example |
|---|---|---|---|
next |
n |
Executes the current line and moves to the next one. | n |
step |
s |
Steps into a function call if the current line calls one. | s |
continue |
c |
Continues execution until the next breakpoint or the program ends. | c |
list |
l |
Shows the source code around the current line. | l |
longlist |
ll |
Shows the entire function or context's source code. | ll |
print |
p |
Evaluates and prints the value of an expression. | p item |
pp |
pp |
"Pretty prints" an expression, useful for complex data. | pp my_data |
quit |
q |
Exits the debugger and terminates the program. | q |
where |
w |
Shows the call stack (the list of functions that led to the current point). | w |
help |
h |
Shows help for a specific command or lists all commands. | h next |
args |
a |
Shows the arguments of the current function. | a |
Practical Debugging Session
Let's go back to our first example where the debugger started on the exception.
> /path/to/your/project/buggy_script.py(7)process_data()
-> processed_item = item * 2
(Pdb)
-
Inspect the variable that caused the error. The error happened with
item. Let's see whatitemis.(Pdb) p item 'four' (Pdb)Now we know
itemis a string, which confirms theTypeError. -
See the call stack to understand the context.
(Pdb) w /path/to/your/project/buggy_script.py(12)<module>() final_result = process_data(my_data) /path/to/your/project/buggy_script.py(7)process_data() -> processed_item = item * 2 (Pdb)This shows we are inside the
process_datafunction, which was called from the main part of the script. -
Inspect the loop's data to see the full list. We need to see the
datalist to understand what we're working with.(Pdb) p data [1, 2, 3, 'four', 5] (Pdb)Now we can see the problem: the list contains a string
'four'. -
Continue Execution to see the next error. We've identified the problem. Let's see what happens next. We can't fix it here, but we can see if another error occurs.
(Pdb) c Traceback (most recent call last): File "buggy_script.py", line 12, in <module> final_result = process_data(my_data) File "buggy_script.py", line 7, in process_data processed_item = item * 2 TypeError: can't multiply sequence by non-int of type 'int' > /path/to/your/project/buggy_script.py(7)process_data() -> processed_item = item * 2 (Pdb)We are back at the same spot because the loop will keep hitting the same error for the string
'four''. To get out, we can usequit`. -
Quit the debugger.
(Pdb) q Really quit? (y/n) y
Advanced Tip: Conditional Breakpoints
You can make a breakpoint() conditional by passing a condition as an argument. The debugger will only pause if the condition evaluates to True.
Imagine you have a long loop and only want to stop when item is 'four'.
# buggy_script.py
def process_data(data):
"""Processes a list of numbers."""
print("Starting processing...")
result = []
for item in data:
# Only stop if item is the string 'four'
breakpoint(condition=item == 'four')
processed_item = item * 2
result.append(processed_item)
return result
Now, when you run the script, the debugger will pause inside the loop only when item is 'four', skipping all the other iterations. This is incredibly useful for large datasets or long loops.
Summary
| Method | When to Use | How to Start |
|---|---|---|
| On Exception | When your script crashes and you want to inspect the state at the point of failure. | export PYTHONBREAKPOINT=0 then run your script. |
breakpoint() |
When you want to pause execution at a specific, known point in your code to inspect the state. | Add breakpoint() to your code and run the script. |
| Command Line | When you want to start debugging from the very beginning of a script. | python -m ipdb your_script.py |
ipdb is an indispensable tool for any Python developer. Mastering it will save you countless hours of frustration and make debugging a much more efficient and less painful process.
