Key Takeaways: Error Handling
One-Sentence Summary
Python's exception system lets you write programs that handle errors gracefully instead of crashing — and the EAFP philosophy ("Easier to Ask Forgiveness than Permission") means you should try operations and handle failures, rather than checking every precondition upfront.
Three Types of Errors
| Type | When Caught | Example | How to Fix |
|---|---|---|---|
| Syntax error | Before running (parsing) | print("hello" |
Fix the syntax |
| Runtime error (exception) | During execution | int("abc") |
Handle with try/except |
| Logic error | Never (produces wrong output) | Using - 32 instead of + 32 |
Test and debug (Chapter 13) |
The try/except/else/finally Pattern
try:
# Code that might fail
except SpecificError:
# Handle that specific error
else:
# Runs ONLY if try succeeded (no exception)
finally:
# ALWAYS runs — cleanup goes here
| Clause | When It Runs | Purpose |
|---|---|---|
try |
Always (first) | Attempt the risky operation |
except |
Only if a matching exception occurs | Handle the error |
else |
Only if NO exception occurs | Success-only code (keep try short) |
finally |
ALWAYS, no matter what | Resource cleanup (close files, etc.) |
Raising Exceptions
def validate_score(score):
if score < 0 or score > 100:
raise ValueError(f"Score must be 0-100, got {score}")
return score
Guidelines:
- Use the most specific exception type (ValueError, not Exception)
- Include the actual problematic value in the message
- Raise early (in the function), catch late (in the caller)
LBYL vs EAFP (Threshold Concept)
| LBYL ("Look Before You Leap") | EAFP ("Easier to Ask Forgiveness") |
|---|---|
| Check conditions first, then act | Try the operation, handle failure |
if key in d: val = d[key] |
try: val = d[key] except KeyError: ... |
| Extra checks clutter happy path | Happy path is clear |
| Race condition risk (check-then-act gap) | No race condition |
| Better for expensive operations | Better for most Python code |
Python's default: EAFP. Use LBYL only when you have a specific reason.
Custom Exceptions
class TaskFlowError(Exception):
"""Base exception for TaskFlow."""
pass
class TaskNotFoundError(TaskFlowError):
pass
Custom exceptions add clarity (the name tells you what went wrong) and enable selective catching.
Anti-Patterns to Avoid
| Anti-Pattern | Why It's Bad | What to Do Instead |
|---|---|---|
Bare except: |
Catches everything, including Ctrl+C | except SpecificError: |
except Exception: |
Hides bugs from unrelated code | Catch specific types |
except: pass |
Silently loses errors | Log or report the error |
Huge try blocks |
Can't tell which line caused the exception | Keep try blocks short |
Key Patterns from This Chapter
- Retry loop:
while True: try: ... return value except: ... print("try again") - Graceful degradation: If a file is corrupt, start fresh instead of crashing
- Raise early, catch late: Functions validate and raise; callers decide how to respond
- Resource cleanup with finally: Guarantee files/connections are closed
Reading Tracebacks
Read from the bottom up: 1. Last line = exception type and message (the "what") 2. Lines above = the call chain that led to the error (the "where") 3. Top line = where the program started the failing chain
What's Next
Chapter 12: Organize code into modules and packages — split TaskFlow into separate importable files. Chapter 13: Testing — systematically verify your error handling works.