Skip to Content
Course content

147: Debugging with pdb

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Listen, we've all been there: you've got a bug that only happens on the 47th iteration of a loop, and you're currently staring at a screen filled with twenty different print("HERE 1") and print("HERE 2") statements. It's tedious, it clutters your code, and frankly, it's a waste of your time. That's why we use pdb, Python's built-in debugger. It lets you freeze time and poke around the internals of your program while it's actually running.

Setting up a buggy order calculator

I've put together a small script that calculates the total cost of a shopping cart. It takes a list of items and applies a discount if the total is over a certain amount. On the surface, it looks fine, but it's crashing on certain datasets. Let's look at the code:

def calculate_total(cart, discount_threshold=100):
    total = 0
    for item in cart:
        total += item['price'] * item['quantity']
    
    if total > discount_threshold:
        total -= 10
    return total

orders = [
    {'name': 'Keyboard', 'price': 50, 'quantity': 1},
    {'name': 'Mouse', 'price': 25, 'quantity': 2},
    {'name': 'USB Cable', 'price': '10', 'quantity': 1}, # Potential issue here
]

print(f"Final total: {calculate_total(orders)}")

If you run this, you'll get a TypeError because I've sneakily put a string '10' where a number should be. Now, I could just look at the traceback and fix it, but in a real-world app with 5,000 lines of code, you won't always be that lucky. Let's use pdb to find it.

Dropping a breakpoint into the chaos

In modern Python (3.7+), we have the breakpoint() function. It's a shortcut that tells Python: "Stop everything right here and give me an interactive shell." I'll place it right inside the loop where the calculation happens.

def calculate_total(cart, discount_threshold=100):
    total = 0
    for item in cart:
        breakpoint()  # Execution will freeze here
        total += item['price'] * item['quantity']
    
    if total > discount_threshold:
        total -= 10
    return total

When I run this now, the program doesn't just crash; it stops. My terminal will show a (Pdb) prompt. This is where the magic happens. I can now type commands to inspect the state of the program.

Hunting for the culprit with pdb commands

Once I'm at the prompt, I have a few essential tools. I usually start with n (next) to execute the current line and move to the next one, and p (print) to see what a variable actually holds.

Here is how my session looks:

(Pdb) n
> total += item['price'] * item['quantity']
(Pdb) p item
{'name': 'Keyboard', 'price': 50, 'quantity': 1}
(Pdb) n
> for item in cart:
(Pdb) n
> total += item['price'] * item['quantity']
(Pdb) p item
{'name': 'Mouse', 'price': 25, 'quantity': 2}

Everything looks fine so far. I'll keep hitting n until I hit the third item.

Realizing I looked at the wrong variable

At this point, I might mistakenly assume the bug is in the total variable or the discount_threshold. I'll spend a minute checking the total: (Pdb) p total. It's 100. I'm thinking, "Wait, is the discount logic failing?"

But then I hit n again and—boom—the TypeError hits. I realize I was focusing on the result instead of the input. I step back and look at the item variable for this specific iteration:

(Pdb) p item
{'name': 'USB Cable', 'price': '10', 'quantity': 1}

There it is. '10' is a string. You can't multiply a string by an integer in the way I intended here (well, you can, but Python will just repeat the string ten times, which isn't what we want for a price). Now that I've found the culprit using pdb, I can exit the debugger by typing q (quit) and fix the data or add a type conversion like float(item['price']) to the code.




📋 Practical Task

Debug the Broken Inventory Valuation Script

You have been handed a script that calculates the total value of a warehouse inventory. However, the script is crashing with a TypeError on some entries. Your goal is to use breakpoint() and pdb to identify exactly which item in the list is causing the crash and why.

def get_inventory_value(inventory):
    grand_total = 0
    for item in inventory:
        # The crash happens somewhere in this loop
        value = item['stock'] * item['unit_cost']
        grand_total += value
    return grand_total

warehouse_data = [
    {'item': 'Widget A', 'stock': 20, 'unit_cost': 12.50},
    {'item': 'Widget B', 'stock': 5, 'unit_cost': 45.00},
    {'item': 'Widget C', 'stock': '10', 'unit_cost': 2.00},
    {'item': 'Widget D', 'stock': 100, 'unit_cost': 0.50},
]

try:
    print(f"Total Value: {get_inventory_value(warehouse_data)}")
except TypeError as e:
    print(f"Caught an error: {e}")

Your Task:

  • Insert a breakpoint() inside the for loop.
  • Run the script and use the p item command to inspect the dictionary during each iteration.
  • Identify which item has the incorrect data type.
  • Fix the get_inventory_value function so that it converts the stock and unit_cost to numbers (float or int) before multiplying, ensuring the script runs successfully regardless of whether the input is a string or a number.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.