Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
147: Debugging with pdb
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 theforloop. - Run the script and use the
p itemcommand to inspect the dictionary during each iteration. - Identify which item has the incorrect data type.
- Fix the
get_inventory_valuefunction so that it converts thestockandunit_costto numbers (float or int) before multiplying, ensuring the script runs successfully regardless of whether the input is a string or a number.
There are no comments for now.