breakpoint() and pdb Basics¶
Use breakpoint() to start the debugger and understand pdb for interactive debugging.
Mental Model
Calling breakpoint() is like pressing pause on a running program. Execution freezes at that line and drops you into an interactive shell where you can inspect variables, step through code one line at a time, and test expressions live. It is the fastest way to see what your code is actually doing versus what you think it is doing.
breakpoint() Function¶
Add breakpoints to pause execution for inspection.
```python def calculate(x, y): result = x + y breakpoint() # Debugger will start here return result * 2
When executed, this will start pdb debugger¶
You can inspect variables and step through code¶
print("Debugger example") ```
``` Debugger example
/path/to/script.py(3)calculate() -> breakpoint() ```
pdb Basics¶
Understand pdb debugger and basic commands.
```python import pdb
def debug_function(items): total = 0 for i, item in enumerate(items): # Start debugger at specific point if item > 5: pdb.set_trace() total += item return total
Debugger commands:¶
l - list code¶
n - next line¶
s - step into function¶
c - continue¶
p variable - print variable¶
pp dict - pretty print¶
result = debug_function([1, 2, 3, 6, 7]) print(f"Result: {result}") ```
Result: 19
Exercises¶
Exercise 1.
Write a function find_first_negative that takes a list of numbers and returns the index of the first negative number. Insert a breakpoint() call just before the return statement so you can inspect the variables when debugging. Remove the breakpoint after testing. For example, find_first_negative([3, 7, -2, 5]) should return 2.
Solution to Exercise 1
```python def find_first_negative(numbers): for i, num in enumerate(numbers): if num < 0: # breakpoint() # Uncomment to debug return i return -1
Test¶
print(find_first_negative([3, 7, -2, 5])) # 2 print(find_first_negative([1, 2, 3])) # -1 ```
Exercise 2.
Write a function debug_dict_merge that takes two dictionaries and merges them. If there are duplicate keys, the function should keep the higher value. Add a conditional pdb.set_trace() that only triggers when a duplicate key is found. For example, debug_dict_merge({"a": 1, "b": 5}, {"b": 3, "c": 4}) should return {"a": 1, "b": 5, "c": 4}.
Solution to Exercise 2
```python import pdb
def debug_dict_merge(d1, d2): result = d1.copy() for key, value in d2.items(): if key in result: # pdb.set_trace() # Uncomment to debug duplicates result[key] = max(result[key], value) else: result[key] = value return result
Test¶
merged = debug_dict_merge({"a": 1, "b": 5}, {"b": 3, "c": 4}) print(merged) # {'a': 1, 'b': 5, 'c': 4} ```
Exercise 3.
Write a function trace_recursive_sum that recursively sums a list of numbers. Use breakpoint() with a condition to only pause when the list has exactly 2 elements remaining. This demonstrates conditional breakpoint placement for debugging recursion.
Solution to Exercise 3
```python def trace_recursive_sum(numbers): if len(numbers) == 0: return 0 if len(numbers) == 1: return numbers[0] # if len(numbers) == 2: # breakpoint() # Uncomment to debug mid = len(numbers) // 2 left = trace_recursive_sum(numbers[:mid]) right = trace_recursive_sum(numbers[mid:]) return left + right
Test¶
print(trace_recursive_sum([1, 2, 3, 4, 5])) # 15 print(trace_recursive_sum([10])) # 10 ```