Python Notes
Master Python debugging — print debugging, pdb debugger, VS Code debugger, logging strategies, unit testing with pytest, profiling, and systematic debugging workflows for finding and fixing bugs quickly.
Debugging is the process of finding and fixing bugs in your code. Professional developers spend significant time debugging — mastering these techniques will make you dramatically more productive.
The Debugging Mindset
Before diving into tools, adopt this mindset:
- Reproduce the bug — can you consistently trigger it?
- Isolate the problem — narrow down which code causes it
- Understand what's happening — don't guess; verify your assumptions
- Fix one thing at a time — avoid multiple simultaneous changes
- Verify the fix — confirm it works and didn't break anything else
Print Debugging (Quick and Easy)
Using breakpoint() and pdb
Python's built-in debugger pdb lets you step through code interactively:
def process_orders(orders):
total = 0
for i, order in enumerate(orders):
breakpoint() # Pause execution here (Python 3.7+)
# Old way: import pdb; pdb.set_trace()
amount = order.get('amount', 0)
total += amount
return totalPDB Commands Reference
pdb Commands:
n (next) — Execute current line, go to next
s (step) — Step INTO function calls
c (continue) — Continue until next breakpoint
q (quit) — Quit debugger
p expr — Print the value of expression
pp expr — Pretty print the value
l (list) — Show current code context (11 lines)
ll (longlist) — Show full function source
w (where) — Show call stack
u (up) — Move up the call stack
d (down) — Move down the call stack
b 25 — Set breakpoint at line 25
b func_name — Set breakpoint at function
cl — Clear all breakpoints
h (help) — Show help
h command — Help for specific command
! expr — Execute any Python expression
!x = 5 — Change variable value during debuggingConditional Breakpoints
# Set a breakpoint only when a condition is true
def process_items(items):
for i, item in enumerate(items):
if item < 0:
breakpoint() # Only stops when negative item found
process(item)
# In pdb — set conditional breakpoint
# (Pdb) b 45, x > 100 ← Break at line 45 only when x > 100
# (Pdb) b my_func, n > 50 ← Break in my_func when n > 50The icecream Library (Better print debugging)
pip install icecreamfrom icecream import ic
def calculate(a, b):
ic(a, b) # ic| a: 5, b: 3
result = a + b
ic(result) # ic| result: 8
ic(a + b * 2, a ** 2) # ic| a + b * 2: 11, a ** 2: 25
return result
# Auto-includes file, line, and variable names
# ic| my_script.py:6 in calculate()- result: 8
# Disable for production
ic.disable()
# ic.enable() # Re-enable
# Configure prefix
ic.configureOutput(prefix='🐛 Debug: ')Logging-Based Debugging
Assertions for Debugging
def calculate_percentage(value, total):
"""Calculate what percentage value is of total."""
assert total != 0, f"Total cannot be zero! Got total={total}"
assert isinstance(value, (int, float)), f"value must be numeric, got {type(value)}"
assert isinstance(total, (int, float)), f"total must be numeric, got {type(total)}"
assert 0 <= value <= total, f"value ({value}) must be between 0 and total ({total})"
return (value / total) * 100
# Assertions can be disabled in production with:
# python -O my_script.py (optimization flag disables assert)
# Use assert for:
# - Checking function preconditions
# - Verifying invariants
# - Documenting assumptions
# Don't use assert for:
# - Input validation from users (use if/raise instead)
# - Security checks (can be disabled!)VS Code Debugging
Configure launch.json in .vscode/:
VS Code debugging features:
- Breakpoints — Click the gutter (line numbers) to set
- Conditional breakpoints — Right-click breakpoint → Edit condition
- Watch variables — Add expressions to watch panel
- Call stack — See how you got to current line
- Debug console — Evaluate expressions while paused
Debugging with pytest
Performance Debugging (Profiling)
# Method 1: Simple time measurement
import time
start = time.perf_counter()
# ... your code ...
end = time.perf_counter()
print(f"Elapsed: {end - start:.4f}s")
# Method 2: timeit for microbenchmarks
import timeit
# Benchmark a single expression
t = timeit.timeit('sum(range(1000))', number=10000)
print(f"Average: {t/10000*1000:.4f}ms")
# Method 3: cProfile — function-level profiling
import cProfile
import pstats
# Profile a function
cProfile.run('my_function()', 'profile_stats')
# Analyze results
stats = pstats.Stats('profile_stats')
stats.sort_stats('cumulative') # Sort by cumulative time
stats.print_stats(20) # Show top 20 functions
# Or profile from command line:
# python -m cProfile -s cumulative my_script.py
# Method 4: line_profiler — line-by-line
# pip install line_profiler
# @profile decorator (from line_profiler)
# kernprof -l -v my_script.py
# Method 5: memory_profiler
# pip install memory_profiler
# @profile decorator
# python -m memory_profiler my_script.pyDebugging Patterns
Bisect Debugging
# When you don't know where the bug is, use divide and conquer
# Add checkpoints to narrow down the problem
def process_large_dataset(data):
# Step 1: Check input
print(f"CHECKPOINT 1: Input has {len(data)} rows")
assert all('id' in item for item in data), "Some items missing 'id'"
# Step 2: After first transformation
transformed = transform_data(data)
print(f"CHECKPOINT 2: After transform: {len(transformed)} rows")
assert len(transformed) == len(data), "Transform changed row count!"
# Step 3: After filter
filtered = filter_data(transformed)
print(f"CHECKPOINT 3: After filter: {len(filtered)} rows")
# Step 4: Final result
result = aggregate(filtered)
print(f"CHECKPOINT 4: Final result: {result}")
return resultRubber Duck Debugging
Simply explain your code out loud (or to a rubber duck):
- Describe what the code is supposed to do
- Describe what it actually does
- Often you'll find the bug while explaining!
Minimal Reproducible Example
Debugging Flask Applications
Summary
Debugging techniques covered:
- ✅ Print debugging with
debug_printhelper - ✅
pdbandbreakpoint()for interactive debugging - ✅ PDB command reference (n, s, c, p, w, b)
- ✅
icecreamfor enhanced print debugging - ✅ Logging strategies for production debugging
- ✅ Assertions for verifying assumptions
- ✅ VS Code debugger configuration
- ✅ pytest debugging flags (
--pdb,-s,-v) - ✅ Performance profiling (cProfile, timeit)
- ✅ Systematic debugging patterns (bisect, minimal repro)
*Next: Learning Resources →*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Python Debugging Techniques.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Python Master Course topic.
Search Terms
python-master-course, python master course, python, master, course, resources, debugging, techniques
Related Python Master Course Topics