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

  1. Retry loop: while True: try: ... return value except: ... print("try again")
  2. Graceful degradation: If a file is corrupt, start fresh instead of crashing
  3. Raise early, catch late: Functions validate and raise; callers decide how to respond
  4. 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.