Debugging Python with Evidence
Classify syntax, runtime, and logic failures; read tracebacks; isolate assumptions; and use assertions, logging, and small tests to find causes.
Before this lesson
Read traceback frames productively
Separate cause from symptom
Create a minimal reproducible case
The short answer
Debug by reproducing the failure, reading the complete traceback, reducing the case, and checking one assumption at a time. Fix the cause, then add a test that would catch the regression. Random edits destroy evidence.
Build the mental model
Syntax errors stop parsing. Runtime exceptions include a type and message plus traceback frames. Logic errors complete without an exception but violate the requirement. Naming the category narrows the next useful observation.
The central idea in this lesson is evidence-driven debugging. Read the rule, predict a concrete outcome, and then run the smallest example that can confirm or reject the prediction. This separates knowledge from familiarity with syntax.
Make the design choice explicit
Start at the exception message and the innermost frame you own, then inspect values entering that operation. Use repr to reveal whitespace, a debugger for changing state, logging for repeatable context, and focused assertions for invariants.
def average(values):
if not values:
raise ValueError("average requires at least one value")
return sum(values) / len(values)
samples = [10, 12, 14]
print(f"Average: {average(samples):.1f}")Expected output
Average: 12.0
Trace the example before running it. Identify each input, transformation, returned value, and side effect. Then change one boundary value and explain why the new behavior follows from the rule rather than memorizing the output.
Recognize failure modes
A broad except Exception that silently continues hides the failure and may corrupt later work. Do not change several variables at once. Preserve the failing input and confirm the repaired code passes both that case and neighboring boundaries.
Use a professional practice loop
Turn the concept into a repeatable workflow: write down the expected behavior, implement one coherent change, run a representative example, and retain a regression check. If the result surprises you, capture the exact input and error before changing anything.
Review the program for names, boundaries, and hidden side effects. A solution is complete when another developer can understand its contract, reproduce its setup, and verify both the successful path and one meaningful failure path.
Quick knowledge check
Answer before you reveal.
01Which traceback frame should you inspect first?
Usually the innermost frame in code you control, while using the exception message and earlier frames for context.
02What four steps make the practice loop reliable?
Predict the behavior, make one coherent change, run it, and retain a check that detects regression.
Exercise
Practice challenge
Create a failing case for a unit-price function, identify the exact violated assumption, repair it with a clear contract, and retain the case as a test.
Requirements
- The successful path produces the documented result
- At least one boundary or invalid case is handled deliberately
- Calculation or domain logic is separated from console interaction
Optional extension: Add one automated regression check for the most important rule.
Open in Python compilerLesson checkpoint
One small step locks it in
Mark this lesson complete, then keep the momentum going.
Clear up the details
Frequently asked questions
Is evidence-driven debugging only important in large programs?
No. Small programs reveal the same rules with less noise, and learning the rule early prevents fragile habits from becoming architecture.
Should I memorize every API used here?
No. Memorize the mental model and how to verify behavior. Use documentation for exact names and parameters when needed.
How do I know the exercise is finished?
Meet every success criterion, test at least one boundary or failure case, and explain why the output follows from the code.