Your program divides user input. If they enter zero, it crashes. Try-except lets you catch the error and respond gracefully - show a message, ask again, or use a default value. Your program keeps running.

Basic try-except

Catch and handle an exception.

example
basic_division.py
Replay: real traced execution (multi-file project)
# Basic try-except for division by zero

def main():
    # Without exception handling (crashes)
    print("Without try-except:")
    # This would crash: result = 10 / 0

    # With exception handling
    print("\nWith try-except:")
    try:
        result = 10 / 0
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero")
        result = None

    print(f"Program continues, result = {result}")


    # Safe division function
    print("\nSafe division:")
    numerator = 20
    denominator = 4

    try:
        answer = numerator / denominator
        print(f"{numerator} / {denominator} = {answer}")
    except ZeroDivisionError:
        print("Cannot divide by zero")
        answer = 0

    # Another example with zero
    print("\nWith zero denominator:")
    a = 15
    b = 0

    try:
        quotient = a / b
        print(f"{a} / {b} = {quotient}")
    except ZeroDivisionError:
        print(f"Cannot divide {a} by zero, using default value")
        quotient = float('inf')  # infinity

    print(f"Final quotient: {quotient}")

if __name__ == "__main__":
    main()
# Basic try-except for division by zero

def main():
    # Without exception handling (crashes)
    print("Without try-except:")
    # This would crash: result = 10 / 0

    # With exception handling
    print("\nWith try-except:")
    try:
        result = 10 / 0
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero")
        result = None

    print(f"Program continues, result = {result}")


    # Safe division function
    print("\nSafe division:")
    numerator = 10
    denominator = 4

    try:
        answer = numerator / denominator
        print(f"{numerator} / {denominator} = {answer}")
    except ZeroDivisionError:
        print("Cannot divide by zero")
        answer = 0

    # Another example with zero
    print("\nWith zero denominator:")
    a = 15
    b = 0

    try:
        quotient = a / b
        print(f"{a} / {b} = {quotient}")
    except ZeroDivisionError:
        print(f"Cannot divide {a} by zero, using default value")
        quotient = float('inf')  # infinity

    print(f"Final quotient: {quotient}")

if __name__ == "__main__":
    main()
# Basic try-except for division by zero

def main():
    # Without exception handling (crashes)
    print("Without try-except:")
    # This would crash: result = 10 / 0

    # With exception handling
    print("\nWith try-except:")
    try:
        result = 10 / 0
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero")
        result = None

    print(f"Program continues, result = {result}")


    # Safe division function
    print("\nSafe division:")
    numerator = 30
    denominator = 4

    try:
        answer = numerator / denominator
        print(f"{numerator} / {denominator} = {answer}")
    except ZeroDivisionError:
        print("Cannot divide by zero")
        answer = 0

    # Another example with zero
    print("\nWith zero denominator:")
    a = 15
    b = 0

    try:
        quotient = a / b
        print(f"{a} / {b} = {quotient}")
    except ZeroDivisionError:
        print(f"Cannot divide {a} by zero, using default value")
        quotient = float('inf')  # infinity

    print(f"Final quotient: {quotient}")

if __name__ == "__main__":
    main()
# Basic try-except for division by zero

def main():
    # Without exception handling (crashes)
    print("Without try-except:")
    # This would crash: result = 10 / 0

    # With exception handling
    print("\nWith try-except:")
    try:
        result = 10 / 0
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero")
        result = None

    print(f"Program continues, result = {result}")


    # Safe division function
    print("\nSafe division:")
    numerator = 50
    denominator = 4

    try:
        answer = numerator / denominator
        print(f"{numerator} / {denominator} = {answer}")
    except ZeroDivisionError:
        print("Cannot divide by zero")
        answer = 0

    # Another example with zero
    print("\nWith zero denominator:")
    a = 15
    b = 0

    try:
        quotient = a / b
        print(f"{a} / {b} = {quotient}")
    except ZeroDivisionError:
        print(f"Cannot divide {a} by zero, using default value")
        quotient = float('inf')  # infinity

    print(f"Final quotient: {quotient}")

if __name__ == "__main__":
    main()
# Basic try-except for division by zero

def main():
    # Without exception handling (crashes)
    print("Without try-except:")
    # This would crash: result = 10 / 0

    # With exception handling
    print("\nWith try-except:")
    try:
        result = 10 / 0
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero")
        result = None

    print(f"Program continues, result = {result}")


    # Safe division function
    print("\nSafe division:")
    numerator = 20
    denominator = 0

    try:
        answer = numerator / denominator
        print(f"{numerator} / {denominator} = {answer}")
    except ZeroDivisionError:
        print("Cannot divide by zero")
        answer = 0

    # Another example with zero
    print("\nWith zero denominator:")
    a = 15
    b = 0

    try:
        quotient = a / b
        print(f"{a} / {b} = {quotient}")
    except ZeroDivisionError:
        print(f"Cannot divide {a} by zero, using default value")
        quotient = float('inf')  # infinity

    print(f"Final quotient: {quotient}")

if __name__ == "__main__":
    main()
# Basic try-except for division by zero

def main():
    # Without exception handling (crashes)
    print("Without try-except:")
    # This would crash: result = 10 / 0

    # With exception handling
    print("\nWith try-except:")
    try:
        result = 10 / 0
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero")
        result = None

    print(f"Program continues, result = {result}")


    # Safe division function
    print("\nSafe division:")
    numerator = 20
    denominator = 2

    try:
        answer = numerator / denominator
        print(f"{numerator} / {denominator} = {answer}")
    except ZeroDivisionError:
        print("Cannot divide by zero")
        answer = 0

    # Another example with zero
    print("\nWith zero denominator:")
    a = 15
    b = 0

    try:
        quotient = a / b
        print(f"{a} / {b} = {quotient}")
    except ZeroDivisionError:
        print(f"Cannot divide {a} by zero, using default value")
        quotient = float('inf')  # infinity

    print(f"Final quotient: {quotient}")

if __name__ == "__main__":
    main()
# Basic try-except for division by zero

def main():
    # Without exception handling (crashes)
    print("Without try-except:")
    # This would crash: result = 10 / 0

    # With exception handling
    print("\nWith try-except:")
    try:
        result = 10 / 0
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero")
        result = None

    print(f"Program continues, result = {result}")


    # Safe division function
    print("\nSafe division:")
    numerator = 20
    denominator = 5

    try:
        answer = numerator / denominator
        print(f"{numerator} / {denominator} = {answer}")
    except ZeroDivisionError:
        print("Cannot divide by zero")
        answer = 0

    # Another example with zero
    print("\nWith zero denominator:")
    a = 15
    b = 0

    try:
        quotient = a / b
        print(f"{a} / {b} = {quotient}")
    except ZeroDivisionError:
        print(f"Cannot divide {a} by zero, using default value")
        quotient = float('inf')  # infinity

    print(f"Final quotient: {quotient}")

if __name__ == "__main__":
    main()
  1. def main(): # Without exception handling (crashes)

    3def main():4    # Without exception handling (crashes)5    print("Without try-except:")6    # This would crash: result = 10 / 07    8    # With exception handling9    print("\nWith try-except:")10    try:
    outputWithout try-except:
    
    With try-except:
  2. result ← None

    12    print(f"Result: {result}")13except ZeroDivisionError:14    print("Error: Cannot divide by zero")15    result→ None = None
    outputError: Cannot divide by zero
  3. numerator ← 20, denominator ← 4

    17print(f"Program continues, result = {resultNone}")1819#@help h120# Without try-except, program crashes at division by zero21# With try-except, we catch the error and program continues22# The except block runs only when that specific error occurs23#@end2425# Safe division function26print("\nSafe division:")27numerator→ 20 = 2028#@numerator=10, 30, 5029denominator→ 4 = 430#@denominator=0, 2, 5
    outputProgram continues, result = None
    
    Safe division:
  4. answer ← 5.0

    32try:33    answer→ 5.0 = numerator20 / denominator434    print(f"{numerator20} / {denominator4} = {answer5.0}")35except ZeroDivisionError:
    output20 / 4 = 5.0
  5. a ← 15, b ← 0

    39# Another example with zero40print("\nWith zero denominator:")41a→ 15 = 1542b→ 0 = 0
    output
    With zero denominator:
  6. try:

    44try:45    quotient = a15 / b046    print(f"{a} / {b} = {quotient}")
  7. quotient ← inf

    46    print(f"{a} / {b} = {quotient}")47except ZeroDivisionError:48    print(f"Cannot divide {a15} by zero, using default value")49    quotient→ inf = float('inf')  # infinity5051print(f"Final quotient: {quotient}")
    outputCannot divide 15 by zero, using default value
  8. print(f"Final quotient: {quotient}")

    51print(f"Final quotient: {quotientinf}")
    outputFinal quotient: inf
  9. main()

    53if __name__ == "__main__":54    main()
  1. def main(): # Without exception handling (crashes)

    3def main():4    # Without exception handling (crashes)5    print("Without try-except:")6    # This would crash: result = 10 / 07    8    # With exception handling9    print("\nWith try-except:")10    try:
    outputWithout try-except:
    
    With try-except:
  2. result ← None

    12    print(f"Result: {result}")13except ZeroDivisionError:14    print("Error: Cannot divide by zero")15    result→ None = None
    outputError: Cannot divide by zero
  3. numerator ← 10, denominator ← 4

    17print(f"Program continues, result = {resultNone}")181920# Safe division function21print("\nSafe division:")22numerator→ 10 = 1023denominator→ 4 = 4
    outputProgram continues, result = None
    
    Safe division:
  4. answer ← 2.5

    25try:26    answer→ 2.5 = numerator10 / denominator427    print(f"{numerator10} / {denominator4} = {answer2.5}")28except ZeroDivisionError:
    output10 / 4 = 2.5
  5. a ← 15, b ← 0

    32# Another example with zero33print("\nWith zero denominator:")34a→ 15 = 1535b→ 0 = 0
    output
    With zero denominator:
  6. try:

    37try:38    quotient = a15 / b039    print(f"{a} / {b} = {quotient}")
  7. quotient ← inf

    39    print(f"{a} / {b} = {quotient}")40except ZeroDivisionError:41    print(f"Cannot divide {a15} by zero, using default value")42    quotient→ inf = float('inf')  # infinity4344print(f"Final quotient: {quotient}")
    outputCannot divide 15 by zero, using default value
  8. print(f"Final quotient: {quotient}")

    44print(f"Final quotient: {quotientinf}")
    outputFinal quotient: inf
  9. main()

    46if __name__ == "__main__":47    main()
  1. def main(): # Without exception handling (crashes)

    3def main():4    # Without exception handling (crashes)5    print("Without try-except:")6    # This would crash: result = 10 / 07    8    # With exception handling9    print("\nWith try-except:")10    try:
    outputWithout try-except:
    
    With try-except:
  2. result ← None

    12    print(f"Result: {result}")13except ZeroDivisionError:14    print("Error: Cannot divide by zero")15    result→ None = None
    outputError: Cannot divide by zero
  3. numerator ← 30, denominator ← 4

    17print(f"Program continues, result = {resultNone}")181920# Safe division function21print("\nSafe division:")22numerator→ 30 = 3023denominator→ 4 = 4
    outputProgram continues, result = None
    
    Safe division:
  4. answer ← 7.5

    25try:26    answer→ 7.5 = numerator30 / denominator427    print(f"{numerator30} / {denominator4} = {answer7.5}")28except ZeroDivisionError:
    output30 / 4 = 7.5
  5. a ← 15, b ← 0

    32# Another example with zero33print("\nWith zero denominator:")34a→ 15 = 1535b→ 0 = 0
    output
    With zero denominator:
  6. try:

    37try:38    quotient = a15 / b039    print(f"{a} / {b} = {quotient}")
  7. quotient ← inf

    39    print(f"{a} / {b} = {quotient}")40except ZeroDivisionError:41    print(f"Cannot divide {a15} by zero, using default value")42    quotient→ inf = float('inf')  # infinity4344print(f"Final quotient: {quotient}")
    outputCannot divide 15 by zero, using default value
  8. print(f"Final quotient: {quotient}")

    44print(f"Final quotient: {quotientinf}")
    outputFinal quotient: inf
  9. main()

    46if __name__ == "__main__":47    main()
  1. def main(): # Without exception handling (crashes)

    3def main():4    # Without exception handling (crashes)5    print("Without try-except:")6    # This would crash: result = 10 / 07    8    # With exception handling9    print("\nWith try-except:")10    try:
    outputWithout try-except:
    
    With try-except:
  2. result ← None

    12    print(f"Result: {result}")13except ZeroDivisionError:14    print("Error: Cannot divide by zero")15    result→ None = None
    outputError: Cannot divide by zero
  3. numerator ← 50, denominator ← 4

    17print(f"Program continues, result = {resultNone}")181920# Safe division function21print("\nSafe division:")22numerator→ 50 = 5023denominator→ 4 = 4
    outputProgram continues, result = None
    
    Safe division:
  4. answer ← 12.5

    25try:26    answer→ 12.5 = numerator50 / denominator427    print(f"{numerator50} / {denominator4} = {answer12.5}")28except ZeroDivisionError:
    output50 / 4 = 12.5
  5. a ← 15, b ← 0

    32# Another example with zero33print("\nWith zero denominator:")34a→ 15 = 1535b→ 0 = 0
    output
    With zero denominator:
  6. try:

    37try:38    quotient = a15 / b039    print(f"{a} / {b} = {quotient}")
  7. quotient ← inf

    39    print(f"{a} / {b} = {quotient}")40except ZeroDivisionError:41    print(f"Cannot divide {a15} by zero, using default value")42    quotient→ inf = float('inf')  # infinity4344print(f"Final quotient: {quotient}")
    outputCannot divide 15 by zero, using default value
  8. print(f"Final quotient: {quotient}")

    44print(f"Final quotient: {quotientinf}")
    outputFinal quotient: inf
  9. main()

    46if __name__ == "__main__":47    main()
  1. def main(): # Without exception handling (crashes)

    3def main():4    # Without exception handling (crashes)5    print("Without try-except:")6    # This would crash: result = 10 / 07    8    # With exception handling9    print("\nWith try-except:")10    try:
    outputWithout try-except:
    
    With try-except:
  2. result ← None

    12    print(f"Result: {result}")13except ZeroDivisionError:14    print("Error: Cannot divide by zero")15    result→ None = None
    outputError: Cannot divide by zero
  3. numerator ← 20, denominator ← 0

    17print(f"Program continues, result = {resultNone}")181920# Safe division function21print("\nSafe division:")22numerator→ 20 = 2023denominator→ 0 = 0
    outputProgram continues, result = None
    
    Safe division:
  4. try:

    25try:26    answer = numerator20 / denominator027    print(f"{numerator} / {denominator} = {answer}")
  5. answer ← 0

    27    print(f"{numerator} / {denominator} = {answer}")28except ZeroDivisionError:29    print("Cannot divide by zero")30    answer→ 0 = 0
    outputCannot divide by zero
  6. a ← 15, b ← 0

    32# Another example with zero33print("\nWith zero denominator:")34a→ 15 = 1535b→ 0 = 0
    output
    With zero denominator:
  7. try:

    37try:38    quotient = a15 / b039    print(f"{a} / {b} = {quotient}")
  8. quotient ← inf

    39    print(f"{a} / {b} = {quotient}")40except ZeroDivisionError:41    print(f"Cannot divide {a15} by zero, using default value")42    quotient→ inf = float('inf')  # infinity4344print(f"Final quotient: {quotient}")
    outputCannot divide 15 by zero, using default value
  9. print(f"Final quotient: {quotient}")

    44print(f"Final quotient: {quotientinf}")
    outputFinal quotient: inf
  10. main()

    46if __name__ == "__main__":47    main()
  1. def main(): # Without exception handling (crashes)

    3def main():4    # Without exception handling (crashes)5    print("Without try-except:")6    # This would crash: result = 10 / 07    8    # With exception handling9    print("\nWith try-except:")10    try:
    outputWithout try-except:
    
    With try-except:
  2. result ← None

    12    print(f"Result: {result}")13except ZeroDivisionError:14    print("Error: Cannot divide by zero")15    result→ None = None
    outputError: Cannot divide by zero
  3. numerator ← 20, denominator ← 2

    17print(f"Program continues, result = {resultNone}")181920# Safe division function21print("\nSafe division:")22numerator→ 20 = 2023denominator→ 2 = 2
    outputProgram continues, result = None
    
    Safe division:
  4. answer ← 10.0

    25try:26    answer→ 10.0 = numerator20 / denominator227    print(f"{numerator20} / {denominator2} = {answer10.0}")28except ZeroDivisionError:
    output20 / 2 = 10.0
  5. a ← 15, b ← 0

    32# Another example with zero33print("\nWith zero denominator:")34a→ 15 = 1535b→ 0 = 0
    output
    With zero denominator:
  6. try:

    37try:38    quotient = a15 / b039    print(f"{a} / {b} = {quotient}")
  7. quotient ← inf

    39    print(f"{a} / {b} = {quotient}")40except ZeroDivisionError:41    print(f"Cannot divide {a15} by zero, using default value")42    quotient→ inf = float('inf')  # infinity4344print(f"Final quotient: {quotient}")
    outputCannot divide 15 by zero, using default value
  8. print(f"Final quotient: {quotient}")

    44print(f"Final quotient: {quotientinf}")
    outputFinal quotient: inf
  9. main()

    46if __name__ == "__main__":47    main()
  1. def main(): # Without exception handling (crashes)

    3def main():4    # Without exception handling (crashes)5    print("Without try-except:")6    # This would crash: result = 10 / 07    8    # With exception handling9    print("\nWith try-except:")10    try:
    outputWithout try-except:
    
    With try-except:
  2. result ← None

    12    print(f"Result: {result}")13except ZeroDivisionError:14    print("Error: Cannot divide by zero")15    result→ None = None
    outputError: Cannot divide by zero
  3. numerator ← 20, denominator ← 5

    17print(f"Program continues, result = {resultNone}")181920# Safe division function21print("\nSafe division:")22numerator→ 20 = 2023denominator→ 5 = 5
    outputProgram continues, result = None
    
    Safe division:
  4. answer ← 4.0

    25try:26    answer→ 4.0 = numerator20 / denominator527    print(f"{numerator20} / {denominator5} = {answer4.0}")28except ZeroDivisionError:
    output20 / 5 = 4.0
  5. a ← 15, b ← 0

    32# Another example with zero33print("\nWith zero denominator:")34a→ 15 = 1535b→ 0 = 0
    output
    With zero denominator:
  6. try:

    37try:38    quotient = a15 / b039    print(f"{a} / {b} = {quotient}")
  7. quotient ← inf

    39    print(f"{a} / {b} = {quotient}")40except ZeroDivisionError:41    print(f"Cannot divide {a15} by zero, using default value")42    quotient→ inf = float('inf')  # infinity4344print(f"Final quotient: {quotient}")
    outputCannot divide 15 by zero, using default value
  8. print(f"Final quotient: {quotient}")

    44print(f"Final quotient: {quotientinf}")
    outputFinal quotient: inf
  9. main()

    46if __name__ == "__main__":47    main()

Code that might fail goes in try. Error handling goes in except.

See Exception Flow

An exception changes the path through the program. These diagrams pin the exact division and parsing examples from this lesson.

ZeroDivisionError jumps to exceptZeroDivisionError jumps to excepttry10 / 0ZeroDivisionErrorexcept blockprogram continuessuccess skipped
`10 / 0` raises `ZeroDivisionError`, so Python skips the success print and runs the matching `except` block.
Each operation lands in one matching handlerEach operation lands in one matching handleroperationrisky stephandlerparseint('123')successparseint('abc')ValueErrordivide10 / 0ZeroDivisionErroraccess[1,2][5]IndexError
The operations list has one successful parse, then a `ValueError`, `ZeroDivisionError`, and `IndexError`.
try-except `try: risky code except ExceptionType: handle it`. Prevents crashes.

Catch index errors

Handle accessing invalid list indices.

scores
index_error.py
Replay: real traced execution (multi-file project)
# Catching IndexError when accessing list elements

def main():
    # Safe list access
    scores = [85, 92, 78, 90, 88]

    print("Scores:", scores)
    print(f"Total scores: {len(scores)}")

    # Access valid index
    try:
        first = scores[0]
        print(f"\nFirst score: {first}")
    except IndexError:
        print("Index out of range")
        first = None

    # Access invalid index
    print("\nAccessing index 10:")
    try:
        value = scores[10]
        print(f"Value: {value}")
    except IndexError:
        print("Error: Index 10 doesn't exist")
        value = None


    # Safe get function
    def safe_get(lst, index, default=0):
        try:
            return lst[index]
        except IndexError:
            return default

    print("\nUsing safe_get:")
    print(f"Index 2: {safe_get(scores, 2)}")
    print(f"Index 99: {safe_get(scores, 99, default=-1)}")

    # Multiple attempts
    indices = [0, 2, 5, 3, 10]
    print("\nAccessing multiple indices:")
    for i in indices:
        try:
            score = scores[i]
            print(f"  scores[{i}] = {score}")
        except IndexError:
            print(f"  scores[{i}] = OUT OF RANGE")

if __name__ == "__main__":
    main()
# Catching IndexError when accessing list elements

def main():
    # Safe list access
    scores = [95, 88, 92]

    print("Scores:", scores)
    print(f"Total scores: {len(scores)}")

    # Access valid index
    try:
        first = scores[0]
        print(f"\nFirst score: {first}")
    except IndexError:
        print("Index out of range")
        first = None

    # Access invalid index
    print("\nAccessing index 10:")
    try:
        value = scores[10]
        print(f"Value: {value}")
    except IndexError:
        print("Error: Index 10 doesn't exist")
        value = None


    # Safe get function
    def safe_get(lst, index, default=0):
        try:
            return lst[index]
        except IndexError:
            return default

    print("\nUsing safe_get:")
    print(f"Index 2: {safe_get(scores, 2)}")
    print(f"Index 99: {safe_get(scores, 99, default=-1)}")

    # Multiple attempts
    indices = [0, 2, 5, 3, 10]
    print("\nAccessing multiple indices:")
    for i in indices:
        try:
            score = scores[i]
            print(f"  scores[{i}] = {score}")
        except IndexError:
            print(f"  scores[{i}] = OUT OF RANGE")

if __name__ == "__main__":
    main()
# Catching IndexError when accessing list elements

def main():
    # Safe list access
    scores = [100, 75, 80, 85, 90]

    print("Scores:", scores)
    print(f"Total scores: {len(scores)}")

    # Access valid index
    try:
        first = scores[0]
        print(f"\nFirst score: {first}")
    except IndexError:
        print("Index out of range")
        first = None

    # Access invalid index
    print("\nAccessing index 10:")
    try:
        value = scores[10]
        print(f"Value: {value}")
    except IndexError:
        print("Error: Index 10 doesn't exist")
        value = None


    # Safe get function
    def safe_get(lst, index, default=0):
        try:
            return lst[index]
        except IndexError:
            return default

    print("\nUsing safe_get:")
    print(f"Index 2: {safe_get(scores, 2)}")
    print(f"Index 99: {safe_get(scores, 99, default=-1)}")

    # Multiple attempts
    indices = [0, 2, 5, 3, 10]
    print("\nAccessing multiple indices:")
    for i in indices:
        try:
            score = scores[i]
            print(f"  scores[{i}] = {score}")
        except IndexError:
            print(f"  scores[{i}] = OUT OF RANGE")

if __name__ == "__main__":
    main()
  1. scores ← [85, 92, 78, 90, 88]

    3def main():4    # Safe list access5    scores→ [85, 92, 78, 90, 88] = [85, 92, 78, 90, 88]6    #@scores=[95, 88, 92], [100, 75, 80, 85, 90]7    8    print("Scores:", scores[85, 92, 78, 90, 88])9    print(f"Total scores: {len(scores[85, 92, 78, 90, 88])}")
    outputScores: [85, 92, 78, 90, 88]
    Total scores: 5
  2. first ← 85

    11# Access valid index12try:13    first→ 85 = scores[0]8514    print(f"\nFirst score: {first85}")15except IndexError:
    output
    First score: 85
  3. print(" Accessing index 10:")

    19# Access invalid index20print("\nAccessing index 10:")21try:
    output
    Accessing index 10:
  4. try:

    20print("\nAccessing index 10:")21try:22    value = scores[10](empty)23    print(f"Value: {value}")
  5. value ← None

    23    print(f"Value: {value}")24except IndexError:25    print("Error: Index 10 doesn't exist")26    value→ None = None
    outputError: Index 10 doesn't exist
  6. print(f"Index 2: {safe_get(scores, 2)}")

    41print("\nUsing safe_get:")42print(f"Index 2: {safe_get(scores[85, 92, 78, 90, 88], 2)}")43print(f"Index 99: {safe_get(scores, 99, default=-1)}")
    output
    Using safe_get:
  7. def safe_get(lst, index, default=0):

    pass 1 of 2
    34# Safe get function35def safe_get(lst[85, 92, 78, 90, 88], index2, default0=0):36    try:37        return lst[index]
  8. try:

    pass 1 of 2
    35def safe_get(lst, index, default=0):36    try:37        return lst[index]7838    except IndexError:
  9. print(f"Index 2: {safe_get(scores, 2)}")

    41print("\nUsing safe_get:")42print(f"Index 2: {safe_get(scores[85, 92, 78, 90, 88], 2)}")43print(f"Index 99: {safe_get(scores[85, 92, 78, 90, 88], 99, default=-1)}")
    outputIndex 2: 78
  10. def safe_get(lst, index, default=0):

    pass 2 of 2
    34# Safe get function35def safe_get(lst[85, 92, 78, 90, 88], index99, default-1=0):36    try:37        return lst[index]
  11. try:

    pass 2 of 2
    35def safe_get(lst, index, default=0):36    try:37        return lst[index](empty)38    except IndexError:
  12. except IndexError:

    37    return lst[index]38except IndexError:39    return default-1
  13. indices ← [0, 2, 5, 3, 10]

    42print(f"Index 2: {safe_get(scores, 2)}")43print(f"Index 99: {safe_get(scores[85, 92, 78, 90, 88], 99, default=-1)}")4445# Multiple attempts46indices→ [0, 2, 5, 3, 10] = [0, 2, 5, 3, 10]47print("\nAccessing multiple indices:")48for i in indices:
    outputIndex 99: -1
    
    Accessing multiple indices:
  14. for i in indices:

    pass 1 of 5
    47print("\nAccessing multiple indices:")48for i0 in indices[0, 2, 5, 3, 10]:49    try:50        score = scores[i]
    All 5 passes — pass 1 is the card above
    passi
    10
    22
    35
    43
    510
  15. score ← 85

    pass 1 of 5
    48for i in indices:49    try:50        score→ 85 = scores[i]8551        print(f"  scores[{i0}] = {score85}")52    except IndexError:
    output  scores[0] = 85
    All 5 passes — pass 1 is the card above
    passscores[i]iscore
    185085
    278278
    3(empty)5
    490390
    5(empty)10
  16. except IndexError:

    pass 1 of 2
    51    print(f"  scores[{i}] = {score}")52except IndexError:53    print(f"  scores[{i5}] = OUT OF RANGE")
    output  scores[5] = OUT OF RANGE
      scores[5] = OUT OF RANGE
  17. except IndexError:

    pass 2 of 2
    51    print(f"  scores[{i}] = {score}")52except IndexError:53    print(f"  scores[{i10}] = OUT OF RANGE")
    output  scores[10] = OUT OF RANGE
      scores[10] = OUT OF RANGE
  18. main()

    55if __name__ == "__main__":56    main()
  1. scores ← [95, 88, 92]

    3def main():4    # Safe list access5    scores→ [95, 88, 92] = [95, 88, 92]6    7    print("Scores:", scores[95, 88, 92])8    print(f"Total scores: {len(scores[95, 88, 92])}")
    outputScores: [95, 88, 92]
    Total scores: 3
  2. first ← 95

    10# Access valid index11try:12    first→ 95 = scores[0]9513    print(f"\nFirst score: {first95}")14except IndexError:
    output
    First score: 95
  3. print(" Accessing index 10:")

    18# Access invalid index19print("\nAccessing index 10:")20try:
    output
    Accessing index 10:
  4. try:

    19print("\nAccessing index 10:")20try:21    value = scores[10](empty)22    print(f"Value: {value}")
  5. value ← None

    22    print(f"Value: {value}")23except IndexError:24    print("Error: Index 10 doesn't exist")25    value→ None = None
    outputError: Index 10 doesn't exist
  6. print(f"Index 2: {safe_get(scores, 2)}")

    35print("\nUsing safe_get:")36print(f"Index 2: {safe_get(scores[95, 88, 92], 2)}")37print(f"Index 99: {safe_get(scores, 99, default=-1)}")
    output
    Using safe_get:
  7. def safe_get(lst, index, default=0):

    pass 1 of 2
    28# Safe get function29def safe_get(lst[95, 88, 92], index2, default0=0):30    try:31        return lst[index]
  8. try:

    pass 1 of 2
    29def safe_get(lst, index, default=0):30    try:31        return lst[index]9232    except IndexError:
  9. print(f"Index 2: {safe_get(scores, 2)}")

    35print("\nUsing safe_get:")36print(f"Index 2: {safe_get(scores[95, 88, 92], 2)}")37print(f"Index 99: {safe_get(scores[95, 88, 92], 99, default=-1)}")
    outputIndex 2: 92
  10. def safe_get(lst, index, default=0):

    pass 2 of 2
    28# Safe get function29def safe_get(lst[95, 88, 92], index99, default-1=0):30    try:31        return lst[index]
  11. try:

    pass 2 of 2
    29def safe_get(lst, index, default=0):30    try:31        return lst[index](empty)32    except IndexError:
  12. except IndexError:

    31    return lst[index]32except IndexError:33    return default-1
  13. indices ← [0, 2, 5, 3, 10]

    36print(f"Index 2: {safe_get(scores, 2)}")37print(f"Index 99: {safe_get(scores[95, 88, 92], 99, default=-1)}")3839# Multiple attempts40indices→ [0, 2, 5, 3, 10] = [0, 2, 5, 3, 10]41print("\nAccessing multiple indices:")42for i in indices:
    outputIndex 99: -1
    
    Accessing multiple indices:
  14. for i in indices:

    pass 1 of 5
    41print("\nAccessing multiple indices:")42for i0 in indices[0, 2, 5, 3, 10]:43    try:44        score = scores[i]
    All 5 passes — pass 1 is the card above
    passi
    10
    22
    35
    43
    510
  15. score ← 95

    pass 1 of 5
    42for i in indices:43    try:44        score→ 95 = scores[i]9545        print(f"  scores[{i0}] = {score95}")46    except IndexError:
    output  scores[0] = 95
    All 5 passes — pass 1 is the card above
    passscores[i]iscore
    195095
    292292
    3(empty)
    4(empty)
    5(empty)
  16. except IndexError:

    pass 1 of 3
    45    print(f"  scores[{i}] = {score}")46except IndexError:47    print(f"  scores[{i5}] = OUT OF RANGE")
    output  scores[5] = OUT OF RANGE
      scores[5] = OUT OF RANGE
    All 3 passes — pass 1 is the card above
    passi
    15
    23
    310
  17. main()

    49if __name__ == "__main__":50    main()
  1. scores ← [100, 75, 80, 85, 90]

    3def main():4    # Safe list access5    scores→ [100, 75, 80, 85, 90] = [100, 75, 80, 85, 90]6    7    print("Scores:", scores[100, 75, 80, 85, 90])8    print(f"Total scores: {len(scores[100, 75, 80, 85, 90])}")
    outputScores: [100, 75, 80, 85, 90]
    Total scores: 5
  2. first ← 100

    10# Access valid index11try:12    first→ 100 = scores[0]10013    print(f"\nFirst score: {first100}")14except IndexError:
    output
    First score: 100
  3. print(" Accessing index 10:")

    18# Access invalid index19print("\nAccessing index 10:")20try:
    output
    Accessing index 10:
  4. try:

    19print("\nAccessing index 10:")20try:21    value = scores[10](empty)22    print(f"Value: {value}")
  5. value ← None

    22    print(f"Value: {value}")23except IndexError:24    print("Error: Index 10 doesn't exist")25    value→ None = None
    outputError: Index 10 doesn't exist
  6. print(f"Index 2: {safe_get(scores, 2)}")

    35print("\nUsing safe_get:")36print(f"Index 2: {safe_get(scores[100, 75, 80, 85, 90], 2)}")37print(f"Index 99: {safe_get(scores, 99, default=-1)}")
    output
    Using safe_get:
  7. def safe_get(lst, index, default=0):

    pass 1 of 2
    28# Safe get function29def safe_get(lst[100, 75, 80, 85, 90], index2, default0=0):30    try:31        return lst[index]
  8. try:

    pass 1 of 2
    29def safe_get(lst, index, default=0):30    try:31        return lst[index]8032    except IndexError:
  9. print(f"Index 2: {safe_get(scores, 2)}")

    35print("\nUsing safe_get:")36print(f"Index 2: {safe_get(scores[100, 75, 80, 85, 90], 2)}")37print(f"Index 99: {safe_get(scores[100, 75, 80, 85, 90], 99, default=-1)}")
    outputIndex 2: 80
  10. def safe_get(lst, index, default=0):

    pass 2 of 2
    28# Safe get function29def safe_get(lst[100, 75, 80, 85, 90], index99, default-1=0):30    try:31        return lst[index]
  11. try:

    pass 2 of 2
    29def safe_get(lst, index, default=0):30    try:31        return lst[index](empty)32    except IndexError:
  12. except IndexError:

    31    return lst[index]32except IndexError:33    return default-1
  13. indices ← [0, 2, 5, 3, 10]

    36print(f"Index 2: {safe_get(scores, 2)}")37print(f"Index 99: {safe_get(scores[100, 75, 80, 85, 90], 99, default=-1)}")3839# Multiple attempts40indices→ [0, 2, 5, 3, 10] = [0, 2, 5, 3, 10]41print("\nAccessing multiple indices:")42for i in indices:
    outputIndex 99: -1
    
    Accessing multiple indices:
  14. for i in indices:

    pass 1 of 5
    41print("\nAccessing multiple indices:")42for i0 in indices[0, 2, 5, 3, 10]:43    try:44        score = scores[i]
    All 5 passes — pass 1 is the card above
    passi
    10
    22
    35
    43
    510
  15. score ← 100

    pass 1 of 5
    42for i in indices:43    try:44        score→ 100 = scores[i]10045        print(f"  scores[{i0}] = {score100}")46    except IndexError:
    output  scores[0] = 100
    All 5 passes — pass 1 is the card above
    passscores[i]iscore
    11000100
    280280
    3(empty)5
    485385
    5(empty)10
  16. except IndexError:

    pass 1 of 2
    45    print(f"  scores[{i}] = {score}")46except IndexError:47    print(f"  scores[{i5}] = OUT OF RANGE")
    output  scores[5] = OUT OF RANGE
      scores[5] = OUT OF RANGE
  17. except IndexError:

    pass 2 of 2
    45    print(f"  scores[{i}] = {score}")46except IndexError:47    print(f"  scores[{i10}] = OUT OF RANGE")
    output  scores[10] = OUT OF RANGE
      scores[10] = OUT OF RANGE
  18. main()

    49if __name__ == "__main__":50    main()

IndexError when accessing index outside list range.

Multiple except blocks

Handle different exceptions differently.

age_str
multiple_except.py
Replay: real traced execution (multi-file project)
# Multiple except blocks for different errors

def main():
    # Parse user input (multiple error types)
    print("Input parsing with multiple exceptions:\n")

    data = {
        "name": "Alice",
        "age": "25",
        "scores": [85, 90, 78]
    }

    # Catch ValueError (bad conversion)
    try:
        age_str = "not a number"
        age = int(age_str)
        print(f"Age: {age}")
    except ValueError:
        print("ValueError: Cannot convert to integer")
        age = 0

    # Catch KeyError (missing key)
    try:
        email = data["email"]  # key doesn't exist
        print(f"Email: {email}")
    except KeyError:
        print("KeyError: 'email' key not found")
        email = "unknown@example.com"


    # Multiple exceptions in one try block
    print("\nProcessing with multiple potential errors:")

    try:
        # Could raise KeyError
        score_str = data["score"]  # missing key
        # Could raise ValueError
        score = int(score_str)
        # Could raise IndexError
        first_score = data["scores"][10]

        print(f"Score: {score}, First: {first_score}")

    except KeyError as e:
        print(f"Missing key: {e}")
    except ValueError as e:
        print(f"Invalid value: {e}")
    except IndexError as e:
        print(f"Index error: {e}")

    # Catch parent exception
    print("\nUsing generic Exception:")

    try:
        result = data["count"] / 0
    except ZeroDivisionError:
        print("Specific: Division by zero")
    except Exception as e:
        print(f"Generic: {type(e).__name__}: {e}")

    # Process list of operations
    operations = [
        ("parse", "123"),
        ("parse", "abc"),
        ("divide", 10, 0),
        ("access", [1, 2], 5)
    ]

    print("\nProcessing operations:")
    for op in operations:
        try:
            if op[0] == "parse":
                result = int(op[1])
                print(f"  Parsed: {result}")
            elif op[0] == "divide":
                result = op[1] / op[2]
                print(f"  Divided: {result}")
            elif op[0] == "access":
                result = op[1][op[2]]
                print(f"  Accessed: {result}")
        except ValueError:
            print(f"  ValueError in {op}")
        except ZeroDivisionError:
            print(f"  ZeroDivisionError in {op}")
        except IndexError:
            print(f"  IndexError in {op}")

if __name__ == "__main__":
    main()
# Multiple except blocks for different errors

def main():
    # Parse user input (multiple error types)
    print("Input parsing with multiple exceptions:\n")

    data = {
        "name": "Alice",
        "age": "25",
        "scores": [85, 90, 78]
    }

    # Catch ValueError (bad conversion)
    try:
        age_str = "30"
        age = int(age_str)
        print(f"Age: {age}")
    except ValueError:
        print("ValueError: Cannot convert to integer")
        age = 0

    # Catch KeyError (missing key)
    try:
        email = data["email"]  # key doesn't exist
        print(f"Email: {email}")
    except KeyError:
        print("KeyError: 'email' key not found")
        email = "unknown@example.com"


    # Multiple exceptions in one try block
    print("\nProcessing with multiple potential errors:")

    try:
        # Could raise KeyError
        score_str = data["score"]  # missing key
        # Could raise ValueError
        score = int(score_str)
        # Could raise IndexError
        first_score = data["scores"][10]

        print(f"Score: {score}, First: {first_score}")

    except KeyError as e:
        print(f"Missing key: {e}")
    except ValueError as e:
        print(f"Invalid value: {e}")
    except IndexError as e:
        print(f"Index error: {e}")

    # Catch parent exception
    print("\nUsing generic Exception:")

    try:
        result = data["count"] / 0
    except ZeroDivisionError:
        print("Specific: Division by zero")
    except Exception as e:
        print(f"Generic: {type(e).__name__}: {e}")

    # Process list of operations
    operations = [
        ("parse", "123"),
        ("parse", "abc"),
        ("divide", 10, 0),
        ("access", [1, 2], 5)
    ]

    print("\nProcessing operations:")
    for op in operations:
        try:
            if op[0] == "parse":
                result = int(op[1])
                print(f"  Parsed: {result}")
            elif op[0] == "divide":
                result = op[1] / op[2]
                print(f"  Divided: {result}")
            elif op[0] == "access":
                result = op[1][op[2]]
                print(f"  Accessed: {result}")
        except ValueError:
            print(f"  ValueError in {op}")
        except ZeroDivisionError:
            print(f"  ZeroDivisionError in {op}")
        except IndexError:
            print(f"  IndexError in {op}")

if __name__ == "__main__":
    main()
# Multiple except blocks for different errors

def main():
    # Parse user input (multiple error types)
    print("Input parsing with multiple exceptions:\n")

    data = {
        "name": "Alice",
        "age": "25",
        "scores": [85, 90, 78]
    }

    # Catch ValueError (bad conversion)
    try:
        age_str = "invalid"
        age = int(age_str)
        print(f"Age: {age}")
    except ValueError:
        print("ValueError: Cannot convert to integer")
        age = 0

    # Catch KeyError (missing key)
    try:
        email = data["email"]  # key doesn't exist
        print(f"Email: {email}")
    except KeyError:
        print("KeyError: 'email' key not found")
        email = "unknown@example.com"


    # Multiple exceptions in one try block
    print("\nProcessing with multiple potential errors:")

    try:
        # Could raise KeyError
        score_str = data["score"]  # missing key
        # Could raise ValueError
        score = int(score_str)
        # Could raise IndexError
        first_score = data["scores"][10]

        print(f"Score: {score}, First: {first_score}")

    except KeyError as e:
        print(f"Missing key: {e}")
    except ValueError as e:
        print(f"Invalid value: {e}")
    except IndexError as e:
        print(f"Index error: {e}")

    # Catch parent exception
    print("\nUsing generic Exception:")

    try:
        result = data["count"] / 0
    except ZeroDivisionError:
        print("Specific: Division by zero")
    except Exception as e:
        print(f"Generic: {type(e).__name__}: {e}")

    # Process list of operations
    operations = [
        ("parse", "123"),
        ("parse", "abc"),
        ("divide", 10, 0),
        ("access", [1, 2], 5)
    ]

    print("\nProcessing operations:")
    for op in operations:
        try:
            if op[0] == "parse":
                result = int(op[1])
                print(f"  Parsed: {result}")
            elif op[0] == "divide":
                result = op[1] / op[2]
                print(f"  Divided: {result}")
            elif op[0] == "access":
                result = op[1][op[2]]
                print(f"  Accessed: {result}")
        except ValueError:
            print(f"  ValueError in {op}")
        except ZeroDivisionError:
            print(f"  ZeroDivisionError in {op}")
        except IndexError:
            print(f"  IndexError in {op}")

if __name__ == "__main__":
    main()
  1. data ← {'name': 'Alice', 'age': '25', 'scores': [85, 90, 78]}

    3def main():4    # Parse user input (multiple error types)5    print("Input parsing with multiple exceptions:\n")6    7    data→ {'name': 'Alice', 'age': '25', 'scores': [85, 90, 78]} = {8        "name": "Alice",9        "age": "25",10        "scores": [85, 90, 78]11    }
    outputInput parsing with multiple exceptions:
  2. age_str ← not a number

    13# Catch ValueError (bad conversion)14try:15    age_str→ not a number = "not a number"16    #@age_str="30", "invalid"17    age = int(age_strnot a number)18    print(f"Age: {age}")
  3. age ← 0

    18    print(f"Age: {age}")19except ValueError:20    print("ValueError: Cannot convert to integer")21    age→ 0 = 0
    outputValueError: Cannot convert to integer
  4. try:

    23# Catch KeyError (missing key)24try:25    email = data["email"](empty)  # key doesn't exist26    print(f"Email: {email}")
  5. email ← unknown@example.com

    26    print(f"Email: {email}")27except KeyError:28    print("KeyError: 'email' key not found")29    email→ unknown@example.com = "unknown@example.com"
    outputKeyError: 'email' key not found
  6. print(" Processing with multiple potential errors:")

    37# Multiple exceptions in one try block38print("\nProcessing with multiple potential errors:")
    output
    Processing with multiple potential errors:
  7. try: # Could raise KeyError

    40try:41    # Could raise KeyError42    score_str = data["score"](empty)  # missing key43    # Could raise ValueError
  8. except KeyError as e:

    50except KeyError as e:51    print(f"Missing key: {e'score'}")52except ValueError as e:
    outputMissing key: 'score'
  9. print(" Using generic Exception:")

    57# Catch parent exception58print("\nUsing generic Exception:")
    output
    Using generic Exception:
  10. try:

    60try:61    result = data["count"](empty) / 062except ZeroDivisionError:
  11. except Exception as e:

    63    print("Specific: Division by zero")64except Exception as e:65    print(f"Generic: {type(e'count').__name__}: {e}")6667# Process list of operations
    outputGeneric: KeyError: 'count'
    Generic: KeyError: 'count'
  12. operations ← [('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)]

    67# Process list of operations68operations→ [('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)] = [69    ("parse", "123"),70    ("parse", "abc"),71    ("divide", 10, 0),72    ("access", [1, 2], 5)73]7475print("\nProcessing operations:")76for op in operations:
    output
    Processing operations:
  13. for op in operations:

    pass 1 of 4
    75print("\nProcessing operations:")76for op('parse', '123') in operations[('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)]:77    try:78        if op[0] == "parse":
    All 4 passes — pass 1 is the card above
    passopop[0]op[1]op[2]op[1][op[2]]result
    1('parse', '123')parse123123
    2('parse', 'abc')parseabc
    3('divide', 10, 0)divide100
    4('access', [1, 2], 5)access(empty)
  14. try:

    pass 1 of 4
    76for op in operations:77    try:78        if op[0] == "parse":79            result = int(op[1])
    All 4 passes — pass 1 is the card above
    passop[0]op[1]opop[2]op[1][op[2]]result
    1parse123123
    2parseabc('parse', 'abc')
    3divide10('divide', 10, 0)0
    4access('access', [1, 2], 5)(empty)
  15. result ← 123

    pass 1 of 2
    77try:78    if op[0]parse == "parse":79        result→ 123 = int(op[1]123)80        print(f"  Parsed: {result123}")81    elif op[0] == "divide":
    output  Parsed: 123
  16. if op[0] == "parse":

    pass 2 of 2
    77try:78    if op[0]parse == "parse":79        result = int(op[1]abc)80        print(f"  Parsed: {result}")
  17. except ValueError:

    86        print(f"  Accessed: {result}")87except ValueError:88    print(f"  ValueError in {op('parse', 'abc')}")89except ZeroDivisionError:
    output  ValueError in ('parse', 'abc')
  18. elif op[0] == "divide":

    80    print(f"  Parsed: {result}")81elif op[0]divide == "divide":82    result = op[1]10 / op[2]083    print(f"  Divided: {result}")
  19. except ZeroDivisionError:

    88    print(f"  ValueError in {op}")89except ZeroDivisionError:90    print(f"  ZeroDivisionError in {op('divide', 10, 0)}")91except IndexError:
    output  ZeroDivisionError in ('divide', 10, 0)
  20. elif op[0] == "access":

    83    print(f"  Divided: {result}")84elif op[0]access == "access":85    result = op[1][op[2]](empty)86    print(f"  Accessed: {result}")
  21. except IndexError:

    90    print(f"  ZeroDivisionError in {op}")91except IndexError:92    print(f"  IndexError in {op('access', [1, 2], 5)}")
    output  IndexError in ('access', [1, 2], 5)
      IndexError in ('access', [1, 2], 5)
  22. main()

    94if __name__ == "__main__":95    main()
  1. data ← {'name': 'Alice', 'age': '25', 'scores': [85, 90, 78]}

    3def main():4    # Parse user input (multiple error types)5    print("Input parsing with multiple exceptions:\n")6    7    data→ {'name': 'Alice', 'age': '25', 'scores': [85, 90, 78]} = {8        "name": "Alice",9        "age": "25",10        "scores": [85, 90, 78]11    }
    outputInput parsing with multiple exceptions:
  2. age_str ← 30, age ← 30

    13# Catch ValueError (bad conversion)14try:15    age_str→ 30 = "30"16    age→ 30 = int(age_str30)17    print(f"Age: {age30}")18except ValueError:
    outputAge: 30
  3. try:

    22# Catch KeyError (missing key)23try:24    email = data["email"](empty)  # key doesn't exist25    print(f"Email: {email}")
  4. email ← unknown@example.com

    25    print(f"Email: {email}")26except KeyError:27    print("KeyError: 'email' key not found")28    email→ unknown@example.com = "unknown@example.com"
    outputKeyError: 'email' key not found
  5. print(" Processing with multiple potential errors:")

    31# Multiple exceptions in one try block32print("\nProcessing with multiple potential errors:")
    output
    Processing with multiple potential errors:
  6. try: # Could raise KeyError

    34try:35    # Could raise KeyError36    score_str = data["score"](empty)  # missing key37    # Could raise ValueError
  7. except KeyError as e:

    44except KeyError as e:45    print(f"Missing key: {e'score'}")46except ValueError as e:
    outputMissing key: 'score'
  8. print(" Using generic Exception:")

    51# Catch parent exception52print("\nUsing generic Exception:")
    output
    Using generic Exception:
  9. try:

    54try:55    result = data["count"](empty) / 056except ZeroDivisionError:
  10. except Exception as e:

    57    print("Specific: Division by zero")58except Exception as e:59    print(f"Generic: {type(e'count').__name__}: {e}")6061# Process list of operations
    outputGeneric: KeyError: 'count'
    Generic: KeyError: 'count'
  11. operations ← [('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)]

    61# Process list of operations62operations→ [('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)] = [63    ("parse", "123"),64    ("parse", "abc"),65    ("divide", 10, 0),66    ("access", [1, 2], 5)67]6869print("\nProcessing operations:")70for op in operations:
    output
    Processing operations:
  12. for op in operations:

    pass 1 of 4
    69print("\nProcessing operations:")70for op('parse', '123') in operations[('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)]:71    try:72        if op[0] == "parse":
    All 4 passes — pass 1 is the card above
    passopop[0]op[1]op[2]op[1][op[2]]result
    1('parse', '123')parse123123
    2('parse', 'abc')parseabc
    3('divide', 10, 0)divide100
    4('access', [1, 2], 5)access(empty)
  13. try:

    pass 1 of 4
    70for op in operations:71    try:72        if op[0] == "parse":73            result = int(op[1])
    All 4 passes — pass 1 is the card above
    passop[0]op[1]opop[2]op[1][op[2]]result
    1parse123123
    2parseabc('parse', 'abc')
    3divide10('divide', 10, 0)0
    4access('access', [1, 2], 5)(empty)
  14. result ← 123

    pass 1 of 2
    71try:72    if op[0]parse == "parse":73        result→ 123 = int(op[1]123)74        print(f"  Parsed: {result123}")75    elif op[0] == "divide":
    output  Parsed: 123
  15. if op[0] == "parse":

    pass 2 of 2
    71try:72    if op[0]parse == "parse":73        result = int(op[1]abc)74        print(f"  Parsed: {result}")
  16. except ValueError:

    80        print(f"  Accessed: {result}")81except ValueError:82    print(f"  ValueError in {op('parse', 'abc')}")83except ZeroDivisionError:
    output  ValueError in ('parse', 'abc')
  17. elif op[0] == "divide":

    74    print(f"  Parsed: {result}")75elif op[0]divide == "divide":76    result = op[1]10 / op[2]077    print(f"  Divided: {result}")
  18. except ZeroDivisionError:

    82    print(f"  ValueError in {op}")83except ZeroDivisionError:84    print(f"  ZeroDivisionError in {op('divide', 10, 0)}")85except IndexError:
    output  ZeroDivisionError in ('divide', 10, 0)
  19. elif op[0] == "access":

    77    print(f"  Divided: {result}")78elif op[0]access == "access":79    result = op[1][op[2]](empty)80    print(f"  Accessed: {result}")
  20. except IndexError:

    84    print(f"  ZeroDivisionError in {op}")85except IndexError:86    print(f"  IndexError in {op('access', [1, 2], 5)}")
    output  IndexError in ('access', [1, 2], 5)
      IndexError in ('access', [1, 2], 5)
  21. main()

    88if __name__ == "__main__":89    main()
  1. data ← {'name': 'Alice', 'age': '25', 'scores': [85, 90, 78]}

    3def main():4    # Parse user input (multiple error types)5    print("Input parsing with multiple exceptions:\n")6    7    data→ {'name': 'Alice', 'age': '25', 'scores': [85, 90, 78]} = {8        "name": "Alice",9        "age": "25",10        "scores": [85, 90, 78]11    }
    outputInput parsing with multiple exceptions:
  2. age_str ← invalid

    13# Catch ValueError (bad conversion)14try:15    age_str→ invalid = "invalid"16    age = int(age_strinvalid)17    print(f"Age: {age}")
  3. age ← 0

    17    print(f"Age: {age}")18except ValueError:19    print("ValueError: Cannot convert to integer")20    age→ 0 = 0
    outputValueError: Cannot convert to integer
  4. try:

    22# Catch KeyError (missing key)23try:24    email = data["email"](empty)  # key doesn't exist25    print(f"Email: {email}")
  5. email ← unknown@example.com

    25    print(f"Email: {email}")26except KeyError:27    print("KeyError: 'email' key not found")28    email→ unknown@example.com = "unknown@example.com"
    outputKeyError: 'email' key not found
  6. print(" Processing with multiple potential errors:")

    31# Multiple exceptions in one try block32print("\nProcessing with multiple potential errors:")
    output
    Processing with multiple potential errors:
  7. try: # Could raise KeyError

    34try:35    # Could raise KeyError36    score_str = data["score"](empty)  # missing key37    # Could raise ValueError
  8. except KeyError as e:

    44except KeyError as e:45    print(f"Missing key: {e'score'}")46except ValueError as e:
    outputMissing key: 'score'
  9. print(" Using generic Exception:")

    51# Catch parent exception52print("\nUsing generic Exception:")
    output
    Using generic Exception:
  10. try:

    54try:55    result = data["count"](empty) / 056except ZeroDivisionError:
  11. except Exception as e:

    57    print("Specific: Division by zero")58except Exception as e:59    print(f"Generic: {type(e'count').__name__}: {e}")6061# Process list of operations
    outputGeneric: KeyError: 'count'
    Generic: KeyError: 'count'
  12. operations ← [('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)]

    61# Process list of operations62operations→ [('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)] = [63    ("parse", "123"),64    ("parse", "abc"),65    ("divide", 10, 0),66    ("access", [1, 2], 5)67]6869print("\nProcessing operations:")70for op in operations:
    output
    Processing operations:
  13. for op in operations:

    pass 1 of 4
    69print("\nProcessing operations:")70for op('parse', '123') in operations[('parse', '123'), ('parse', 'abc'), ('divide', 10, 0), ('access', [1, 2], 5)]:71    try:72        if op[0] == "parse":
    All 4 passes — pass 1 is the card above
    passopop[0]op[1]op[2]op[1][op[2]]result
    1('parse', '123')parse123123
    2('parse', 'abc')parseabc
    3('divide', 10, 0)divide100
    4('access', [1, 2], 5)access(empty)
  14. try:

    pass 1 of 4
    70for op in operations:71    try:72        if op[0] == "parse":73            result = int(op[1])
    All 4 passes — pass 1 is the card above
    passop[0]op[1]opop[2]op[1][op[2]]result
    1parse123123
    2parseabc('parse', 'abc')
    3divide10('divide', 10, 0)0
    4access('access', [1, 2], 5)(empty)
  15. result ← 123

    pass 1 of 2
    71try:72    if op[0]parse == "parse":73        result→ 123 = int(op[1]123)74        print(f"  Parsed: {result123}")75    elif op[0] == "divide":
    output  Parsed: 123
  16. if op[0] == "parse":

    pass 2 of 2
    71try:72    if op[0]parse == "parse":73        result = int(op[1]abc)74        print(f"  Parsed: {result}")
  17. except ValueError:

    80        print(f"  Accessed: {result}")81except ValueError:82    print(f"  ValueError in {op('parse', 'abc')}")83except ZeroDivisionError:
    output  ValueError in ('parse', 'abc')
  18. elif op[0] == "divide":

    74    print(f"  Parsed: {result}")75elif op[0]divide == "divide":76    result = op[1]10 / op[2]077    print(f"  Divided: {result}")
  19. except ZeroDivisionError:

    82    print(f"  ValueError in {op}")83except ZeroDivisionError:84    print(f"  ZeroDivisionError in {op('divide', 10, 0)}")85except IndexError:
    output  ZeroDivisionError in ('divide', 10, 0)
  20. elif op[0] == "access":

    77    print(f"  Divided: {result}")78elif op[0]access == "access":79    result = op[1][op[2]](empty)80    print(f"  Accessed: {result}")
  21. except IndexError:

    84    print(f"  ZeroDivisionError in {op}")85except IndexError:86    print(f"  IndexError in {op('access', [1, 2], 5)}")
    output  IndexError in ('access', [1, 2], 5)
      IndexError in ('access', [1, 2], 5)
  22. main()

    88if __name__ == "__main__":89    main()

Specific exceptions first, general Exception last. Order matters.

Catch parent exception

Catch parent type to handle all subtypes.

index
parent_exception.py
Replay: real traced execution (multi-file project)
# Catching parent exception types

def main():
    # Catch general Exception
    print("Catching general Exception:\n")

    numbers = [10, 20, 30]

    try:
        # Could be any type of error
        index = 5
        value = numbers[index]
        result = value / 0
    except Exception as e:
        # Catches ANY exception
        print(f"Caught: {type(e).__name__}")
        print(f"Message: {e}")


    # Specific vs general order matters
    print("\nException handling order:")

    data = {"x": "not_a_number"}

    try:
        num = int(data["y"])
    except KeyError:
        print("Specific: Missing key")
    except ValueError:
        print("Specific: Bad value")
    except Exception as e:
        print(f"General: {type(e).__name__}")

    # Access exception details
    print("\nException details:")

    items = [1, 2, 3]

    try:
        value = items[10]
    except Exception as e:
        print(f"Type: {type(e).__name__}")
        print(f"Message: {str(e)}")
        print(f"Args: {e.args}")

    # Multiple operations with general catch
    def safe_operate(operation, a, b):
        try:
            if operation == "divide":
                return a / b
            elif operation == "get":
                return a[b]
            elif operation == "parse":
                return int(a)
            else:
                return None
        except Exception as e:
            print(f"  Error in {operation}: {type(e).__name__}")
            return None

    print("\nSafe operations:")
    print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
    print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    # Catch and re-raise pattern
    print("\nLogging then re-raising:")

    try:
        try:
            result = 100 / 0
        except ZeroDivisionError as e:
            print(f"Logging: {e}")
            # Could log to file here
            # Then let it propagate
    except Exception:
        print("Outer handler caught it")

if __name__ == "__main__":
    main()
# Catching parent exception types

def main():
    # Catch general Exception
    print("Catching general Exception:\n")

    numbers = [10, 20, 30]

    try:
        # Could be any type of error
        index = 2
        value = numbers[index]
        result = value / 0
    except Exception as e:
        # Catches ANY exception
        print(f"Caught: {type(e).__name__}")
        print(f"Message: {e}")


    # Specific vs general order matters
    print("\nException handling order:")

    data = {"x": "not_a_number"}

    try:
        num = int(data["y"])
    except KeyError:
        print("Specific: Missing key")
    except ValueError:
        print("Specific: Bad value")
    except Exception as e:
        print(f"General: {type(e).__name__}")

    # Access exception details
    print("\nException details:")

    items = [1, 2, 3]

    try:
        value = items[10]
    except Exception as e:
        print(f"Type: {type(e).__name__}")
        print(f"Message: {str(e)}")
        print(f"Args: {e.args}")

    # Multiple operations with general catch
    def safe_operate(operation, a, b):
        try:
            if operation == "divide":
                return a / b
            elif operation == "get":
                return a[b]
            elif operation == "parse":
                return int(a)
            else:
                return None
        except Exception as e:
            print(f"  Error in {operation}: {type(e).__name__}")
            return None

    print("\nSafe operations:")
    print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
    print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    # Catch and re-raise pattern
    print("\nLogging then re-raising:")

    try:
        try:
            result = 100 / 0
        except ZeroDivisionError as e:
            print(f"Logging: {e}")
            # Could log to file here
            # Then let it propagate
    except Exception:
        print("Outer handler caught it")

if __name__ == "__main__":
    main()
# Catching parent exception types

def main():
    # Catch general Exception
    print("Catching general Exception:\n")

    numbers = [10, 20, 30]

    try:
        # Could be any type of error
        index = 10
        value = numbers[index]
        result = value / 0
    except Exception as e:
        # Catches ANY exception
        print(f"Caught: {type(e).__name__}")
        print(f"Message: {e}")


    # Specific vs general order matters
    print("\nException handling order:")

    data = {"x": "not_a_number"}

    try:
        num = int(data["y"])
    except KeyError:
        print("Specific: Missing key")
    except ValueError:
        print("Specific: Bad value")
    except Exception as e:
        print(f"General: {type(e).__name__}")

    # Access exception details
    print("\nException details:")

    items = [1, 2, 3]

    try:
        value = items[10]
    except Exception as e:
        print(f"Type: {type(e).__name__}")
        print(f"Message: {str(e)}")
        print(f"Args: {e.args}")

    # Multiple operations with general catch
    def safe_operate(operation, a, b):
        try:
            if operation == "divide":
                return a / b
            elif operation == "get":
                return a[b]
            elif operation == "parse":
                return int(a)
            else:
                return None
        except Exception as e:
            print(f"  Error in {operation}: {type(e).__name__}")
            return None

    print("\nSafe operations:")
    print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
    print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    # Catch and re-raise pattern
    print("\nLogging then re-raising:")

    try:
        try:
            result = 100 / 0
        except ZeroDivisionError as e:
            print(f"Logging: {e}")
            # Could log to file here
            # Then let it propagate
    except Exception:
        print("Outer handler caught it")

if __name__ == "__main__":
    main()
# Catching parent exception types

def main():
    # Catch general Exception
    print("Catching general Exception:\n")

    numbers = [10, 20, 30]

    try:
        # Could be any type of error
        index = 15
        value = numbers[index]
        result = value / 0
    except Exception as e:
        # Catches ANY exception
        print(f"Caught: {type(e).__name__}")
        print(f"Message: {e}")


    # Specific vs general order matters
    print("\nException handling order:")

    data = {"x": "not_a_number"}

    try:
        num = int(data["y"])
    except KeyError:
        print("Specific: Missing key")
    except ValueError:
        print("Specific: Bad value")
    except Exception as e:
        print(f"General: {type(e).__name__}")

    # Access exception details
    print("\nException details:")

    items = [1, 2, 3]

    try:
        value = items[10]
    except Exception as e:
        print(f"Type: {type(e).__name__}")
        print(f"Message: {str(e)}")
        print(f"Args: {e.args}")

    # Multiple operations with general catch
    def safe_operate(operation, a, b):
        try:
            if operation == "divide":
                return a / b
            elif operation == "get":
                return a[b]
            elif operation == "parse":
                return int(a)
            else:
                return None
        except Exception as e:
            print(f"  Error in {operation}: {type(e).__name__}")
            return None

    print("\nSafe operations:")
    print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
    print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    # Catch and re-raise pattern
    print("\nLogging then re-raising:")

    try:
        try:
            result = 100 / 0
        except ZeroDivisionError as e:
            print(f"Logging: {e}")
            # Could log to file here
            # Then let it propagate
    except Exception:
        print("Outer handler caught it")

if __name__ == "__main__":
    main()
  1. numbers ← [10, 20, 30]

    3def main():4    # Catch general Exception5    print("Catching general Exception:\n")6    7    numbers→ [10, 20, 30] = [10, 20, 30]
    outputCatching general Exception:
  2. index ← 5

    9try:10    # Could be any type of error11    index→ 5 = 512    #@index=2, 10, 1513    value = numbers[index](empty)14    result = value / 0
  3. except Exception as e: # Catches ANY exception

    14    result = value / 015except Exception as e:16    # Catches ANY exception17    print(f"Caught: {type(elist index out of range).__name__}")18    print(f"Message: {elist index out of range}")1920#@help h1
    outputCaught: IndexError
    Message: list index out of range
    Message: list index out of range
  4. data ← {'x': 'not_a_number'}

    26# Specific vs general order matters27print("\nException handling order:")2829data→ {'x': 'not_a_number'} = {"x": "not_a_number"}
    output
    Exception handling order:
  5. try:

    31try:32    num = int(data["y"](empty))33except KeyError:
  6. except KeyError:

    32    num = int(data["y"])33except KeyError:34    print("Specific: Missing key")35except ValueError:
    outputSpecific: Missing key
  7. items ← [1, 2, 3]

    40# Access exception details41print("\nException details:")4243items→ [1, 2, 3] = [1, 2, 3]
    output
    Exception details:
  8. try:

    45try:46    value = items[10](empty)47except Exception as e:
  9. except Exception as e:

    46    value = items[10]47except Exception as e:48    print(f"Type: {type(elist index out of range).__name__}")49    print(f"Message: {str(elist index out of range)}")50    print(f"Args: {e.args('list index out of range',)}")5152# Multiple operations with general catch
    outputType: IndexError
    Message: list index out of range
    Args: ('list index out of range',)
    Args: ('list index out of range',)
  10. print(" Safe operations:")

    67print("\nSafe operations:")68print(f"divide 10/2: {safe_operate('divide', 10, 2)}")69print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    output
    Safe operations:
  11. def safe_operate(operation, a, b):

    pass 1 of 4
    52# Multiple operations with general catch53def safe_operate(operationdivide, a10, b2):54    try:55        if operation == "divide":
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get[1, 2, 3]5(empty)
    4parseabcNone
  12. try:

    pass 1 of 4
    53def safe_operate(operation, a, b):54    try:55        if operation == "divide":56            return a / b
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get(empty)
    4parseabc
  13. if operation == "divide":

    pass 1 of 2
    54try:55    if operationdivide == "divide":56        return a10 / b257    elif operation == "get":
  14. print(f"divide 10/2: {safe_operate('divide', 10, 2)}")

    67print("\nSafe operations:")68print(f"divide 10/2: {safe_operate('divide', 10, 2)}")69print(f"divide 10/0: {safe_operate('divide', 10, 0)}")70print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    outputdivide 10/2: 5.0
  15. if operation == "divide":

    pass 2 of 2
    54try:55    if operationdivide == "divide":56        return a10 / b057    elif operation == "get":
  16. except Exception as e:

    pass 1 of 3
    62        return None63except Exception as e:64    print(f"  Error in {operationdivide}: {type(edivision by zero).__name__}")65    return None
    output  Error in divide: ZeroDivisionError
    All 3 passes — pass 1 is the card above
    passoperatione
    1dividedivision by zero
    2getlist index out of range
    3parseinvalid literal for int() with base 10: 'abc'
  17. print(f"divide 10/0: {safe_operate('divide', 10, 0)}")

    68print(f"divide 10/2: {safe_operate('divide', 10, 2)}")69print(f"divide 10/0: {safe_operate('divide', 10, 0)}")70print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")71print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputdivide 10/0: None
  18. elif operation == "get":

    56    return a / b57elif operationget == "get":58    return a[b](empty)59elif operation == "parse":
  19. print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")

    69print(f"divide 10/0: {safe_operate('divide', 10, 0)}")70print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")71print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputget [1,2,3][5]: None
  20. elif operation == "parse":

    58    return a[b]59elif operationparse == "parse":60    return int(aabc)61else:
  21. print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    70print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")71print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")7273# Catch and re-raise pattern74print("\nLogging then re-raising:")
    outputparse 'abc': None
    
    Logging then re-raising:
  22. except ZeroDivisionError as e:

    78    result = 100 / 079except ZeroDivisionError as e:80    print(f"Logging: {edivision by zero}")81    # Could log to file here
    outputLogging: division by zero
    Logging: division by zero
  23. main()

    86if __name__ == "__main__":87    main()
  1. numbers ← [10, 20, 30]

    3def main():4    # Catch general Exception5    print("Catching general Exception:\n")6    7    numbers→ [10, 20, 30] = [10, 20, 30]
    outputCatching general Exception:
  2. index ← 2, value ← 30

    9try:10    # Could be any type of error11    index→ 2 = 212    value→ 30 = numbers[index]3013    result = value30 / 014except Exception as e:
  3. except Exception as e: # Catches ANY exception

    13    result = value / 014except Exception as e:15    # Catches ANY exception16    print(f"Caught: {type(edivision by zero).__name__}")17    print(f"Message: {edivision by zero}")18
    outputCaught: ZeroDivisionError
    Message: division by zero
    Message: division by zero
  4. data ← {'x': 'not_a_number'}

    20# Specific vs general order matters21print("\nException handling order:")2223data→ {'x': 'not_a_number'} = {"x": "not_a_number"}
    output
    Exception handling order:
  5. try:

    25try:26    num = int(data["y"](empty))27except KeyError:
  6. except KeyError:

    26    num = int(data["y"])27except KeyError:28    print("Specific: Missing key")29except ValueError:
    outputSpecific: Missing key
  7. items ← [1, 2, 3]

    34# Access exception details35print("\nException details:")3637items→ [1, 2, 3] = [1, 2, 3]
    output
    Exception details:
  8. try:

    39try:40    value = items[10](empty)41except Exception as e:
  9. except Exception as e:

    40    value = items[10]41except Exception as e:42    print(f"Type: {type(elist index out of range).__name__}")43    print(f"Message: {str(elist index out of range)}")44    print(f"Args: {e.args('list index out of range',)}")4546# Multiple operations with general catch
    outputType: IndexError
    Message: list index out of range
    Args: ('list index out of range',)
    Args: ('list index out of range',)
  10. print(" Safe operations:")

    61print("\nSafe operations:")62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    output
    Safe operations:
  11. def safe_operate(operation, a, b):

    pass 1 of 4
    46# Multiple operations with general catch47def safe_operate(operationdivide, a10, b2):48    try:49        if operation == "divide":
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get[1, 2, 3]5(empty)
    4parseabcNone
  12. try:

    pass 1 of 4
    47def safe_operate(operation, a, b):48    try:49        if operation == "divide":50            return a / b
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get(empty)
    4parseabc
  13. if operation == "divide":

    pass 1 of 2
    48try:49    if operationdivide == "divide":50        return a10 / b251    elif operation == "get":
  14. print(f"divide 10/2: {safe_operate('divide', 10, 2)}")

    61print("\nSafe operations:")62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    outputdivide 10/2: 5.0
  15. if operation == "divide":

    pass 2 of 2
    48try:49    if operationdivide == "divide":50        return a10 / b051    elif operation == "get":
  16. except Exception as e:

    pass 1 of 3
    56        return None57except Exception as e:58    print(f"  Error in {operationdivide}: {type(edivision by zero).__name__}")59    return None
    output  Error in divide: ZeroDivisionError
    All 3 passes — pass 1 is the card above
    passoperatione
    1dividedivision by zero
    2getlist index out of range
    3parseinvalid literal for int() with base 10: 'abc'
  17. print(f"divide 10/0: {safe_operate('divide', 10, 0)}")

    62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputdivide 10/0: None
  18. elif operation == "get":

    50    return a / b51elif operationget == "get":52    return a[b](empty)53elif operation == "parse":
  19. print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")

    63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputget [1,2,3][5]: None
  20. elif operation == "parse":

    52    return a[b]53elif operationparse == "parse":54    return int(aabc)55else:
  21. print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")6667# Catch and re-raise pattern68print("\nLogging then re-raising:")
    outputparse 'abc': None
    
    Logging then re-raising:
  22. except ZeroDivisionError as e:

    72    result = 100 / 073except ZeroDivisionError as e:74    print(f"Logging: {edivision by zero}")75    # Could log to file here
    outputLogging: division by zero
    Logging: division by zero
  23. main()

    80if __name__ == "__main__":81    main()
  1. numbers ← [10, 20, 30]

    3def main():4    # Catch general Exception5    print("Catching general Exception:\n")6    7    numbers→ [10, 20, 30] = [10, 20, 30]
    outputCatching general Exception:
  2. index ← 10

    9try:10    # Could be any type of error11    index→ 10 = 1012    value = numbers[index](empty)13    result = value / 0
  3. except Exception as e: # Catches ANY exception

    13    result = value / 014except Exception as e:15    # Catches ANY exception16    print(f"Caught: {type(elist index out of range).__name__}")17    print(f"Message: {elist index out of range}")18
    outputCaught: IndexError
    Message: list index out of range
    Message: list index out of range
  4. data ← {'x': 'not_a_number'}

    20# Specific vs general order matters21print("\nException handling order:")2223data→ {'x': 'not_a_number'} = {"x": "not_a_number"}
    output
    Exception handling order:
  5. try:

    25try:26    num = int(data["y"](empty))27except KeyError:
  6. except KeyError:

    26    num = int(data["y"])27except KeyError:28    print("Specific: Missing key")29except ValueError:
    outputSpecific: Missing key
  7. items ← [1, 2, 3]

    34# Access exception details35print("\nException details:")3637items→ [1, 2, 3] = [1, 2, 3]
    output
    Exception details:
  8. try:

    39try:40    value = items[10](empty)41except Exception as e:
  9. except Exception as e:

    40    value = items[10]41except Exception as e:42    print(f"Type: {type(elist index out of range).__name__}")43    print(f"Message: {str(elist index out of range)}")44    print(f"Args: {e.args('list index out of range',)}")4546# Multiple operations with general catch
    outputType: IndexError
    Message: list index out of range
    Args: ('list index out of range',)
    Args: ('list index out of range',)
  10. print(" Safe operations:")

    61print("\nSafe operations:")62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    output
    Safe operations:
  11. def safe_operate(operation, a, b):

    pass 1 of 4
    46# Multiple operations with general catch47def safe_operate(operationdivide, a10, b2):48    try:49        if operation == "divide":
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get[1, 2, 3]5(empty)
    4parseabcNone
  12. try:

    pass 1 of 4
    47def safe_operate(operation, a, b):48    try:49        if operation == "divide":50            return a / b
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get(empty)
    4parseabc
  13. if operation == "divide":

    pass 1 of 2
    48try:49    if operationdivide == "divide":50        return a10 / b251    elif operation == "get":
  14. print(f"divide 10/2: {safe_operate('divide', 10, 2)}")

    61print("\nSafe operations:")62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    outputdivide 10/2: 5.0
  15. if operation == "divide":

    pass 2 of 2
    48try:49    if operationdivide == "divide":50        return a10 / b051    elif operation == "get":
  16. except Exception as e:

    pass 1 of 3
    56        return None57except Exception as e:58    print(f"  Error in {operationdivide}: {type(edivision by zero).__name__}")59    return None
    output  Error in divide: ZeroDivisionError
    All 3 passes — pass 1 is the card above
    passoperatione
    1dividedivision by zero
    2getlist index out of range
    3parseinvalid literal for int() with base 10: 'abc'
  17. print(f"divide 10/0: {safe_operate('divide', 10, 0)}")

    62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputdivide 10/0: None
  18. elif operation == "get":

    50    return a / b51elif operationget == "get":52    return a[b](empty)53elif operation == "parse":
  19. print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")

    63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputget [1,2,3][5]: None
  20. elif operation == "parse":

    52    return a[b]53elif operationparse == "parse":54    return int(aabc)55else:
  21. print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")6667# Catch and re-raise pattern68print("\nLogging then re-raising:")
    outputparse 'abc': None
    
    Logging then re-raising:
  22. except ZeroDivisionError as e:

    72    result = 100 / 073except ZeroDivisionError as e:74    print(f"Logging: {edivision by zero}")75    # Could log to file here
    outputLogging: division by zero
    Logging: division by zero
  23. main()

    80if __name__ == "__main__":81    main()
  1. numbers ← [10, 20, 30]

    3def main():4    # Catch general Exception5    print("Catching general Exception:\n")6    7    numbers→ [10, 20, 30] = [10, 20, 30]
    outputCatching general Exception:
  2. index ← 15

    9try:10    # Could be any type of error11    index→ 15 = 1512    value = numbers[index](empty)13    result = value / 0
  3. except Exception as e: # Catches ANY exception

    13    result = value / 014except Exception as e:15    # Catches ANY exception16    print(f"Caught: {type(elist index out of range).__name__}")17    print(f"Message: {elist index out of range}")18
    outputCaught: IndexError
    Message: list index out of range
    Message: list index out of range
  4. data ← {'x': 'not_a_number'}

    20# Specific vs general order matters21print("\nException handling order:")2223data→ {'x': 'not_a_number'} = {"x": "not_a_number"}
    output
    Exception handling order:
  5. try:

    25try:26    num = int(data["y"](empty))27except KeyError:
  6. except KeyError:

    26    num = int(data["y"])27except KeyError:28    print("Specific: Missing key")29except ValueError:
    outputSpecific: Missing key
  7. items ← [1, 2, 3]

    34# Access exception details35print("\nException details:")3637items→ [1, 2, 3] = [1, 2, 3]
    output
    Exception details:
  8. try:

    39try:40    value = items[10](empty)41except Exception as e:
  9. except Exception as e:

    40    value = items[10]41except Exception as e:42    print(f"Type: {type(elist index out of range).__name__}")43    print(f"Message: {str(elist index out of range)}")44    print(f"Args: {e.args('list index out of range',)}")4546# Multiple operations with general catch
    outputType: IndexError
    Message: list index out of range
    Args: ('list index out of range',)
    Args: ('list index out of range',)
  10. print(" Safe operations:")

    61print("\nSafe operations:")62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
    output
    Safe operations:
  11. def safe_operate(operation, a, b):

    pass 1 of 4
    46# Multiple operations with general catch47def safe_operate(operationdivide, a10, b2):48    try:49        if operation == "divide":
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get[1, 2, 3]5(empty)
    4parseabcNone
  12. try:

    pass 1 of 4
    47def safe_operate(operation, a, b):48    try:49        if operation == "divide":50            return a / b
    All 4 passes — pass 1 is the card above
    passoperationaba[b]
    1divide102
    2divide100
    3get(empty)
    4parseabc
  13. if operation == "divide":

    pass 1 of 2
    48try:49    if operationdivide == "divide":50        return a10 / b251    elif operation == "get":
  14. print(f"divide 10/2: {safe_operate('divide', 10, 2)}")

    61print("\nSafe operations:")62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
    outputdivide 10/2: 5.0
  15. if operation == "divide":

    pass 2 of 2
    48try:49    if operationdivide == "divide":50        return a10 / b051    elif operation == "get":
  16. except Exception as e:

    pass 1 of 3
    56        return None57except Exception as e:58    print(f"  Error in {operationdivide}: {type(edivision by zero).__name__}")59    return None
    output  Error in divide: ZeroDivisionError
    All 3 passes — pass 1 is the card above
    passoperatione
    1dividedivision by zero
    2getlist index out of range
    3parseinvalid literal for int() with base 10: 'abc'
  17. print(f"divide 10/0: {safe_operate('divide', 10, 0)}")

    62print(f"divide 10/2: {safe_operate('divide', 10, 2)}")63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputdivide 10/0: None
  18. elif operation == "get":

    50    return a / b51elif operationget == "get":52    return a[b](empty)53elif operation == "parse":
  19. print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")

    63print(f"divide 10/0: {safe_operate('divide', 10, 0)}")64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
    outputget [1,2,3][5]: None
  20. elif operation == "parse":

    52    return a[b]53elif operationparse == "parse":54    return int(aabc)55else:
  21. print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")

    64print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")65print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")6667# Catch and re-raise pattern68print("\nLogging then re-raising:")
    outputparse 'abc': None
    
    Logging then re-raising:
  22. except ZeroDivisionError as e:

    72    result = 100 / 073except ZeroDivisionError as e:74    print(f"Logging: {edivision by zero}")75    # Could log to file here
    outputLogging: division by zero
    Logging: division by zero
  23. main()

    80if __name__ == "__main__":81    main()

Catching Exception catches (almost) everything. Be specific when possible.

Finally block

Code that always runs, even after exception.

value
finally_block.py
Replay: real traced execution (multi-file project)
# Finally block for cleanup

def main():
    # Finally always executes
    print("Finally block basics:\n")

    try:
        print("In try block")
        result = 10 / 2
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("In except block")
    finally:
        print("In finally block (always runs)")

    # Finally runs even with exception
    print("\nWith exception:")

    try:
        print("In try block")
        result = 10 / 0  # raises error
        print("This won't print")
    except ZeroDivisionError:
        print("In except block")
    finally:
        print("In finally block (runs despite error)")


    # Simulated file handling
    def process_file(filename):
        file_handle = None
        try:
            print(f"\nOpening {filename}")
            file_handle = f"<handle:{filename}>"

            if "error" in filename:
                raise ValueError("Simulated read error")

            print(f"Processing {filename}")
            return "SUCCESS"

        except ValueError as e:
            print(f"Error: {e}")
            return "FAILED"
        finally:
            if file_handle:
                print(f"Closing {file_handle}")

    result1 = process_file("data.txt")
    print(f"Result: {result1}")

    result2 = process_file("error.txt")
    print(f"Result: {result2}")

    # Try-except-else-finally (complete form)
    print("\nComplete form:")

    value = "123"

    try:
        num = int(value)
    except ValueError:
        print("Conversion failed")
        num = 0
    else:
        # Runs only if NO exception
        print(f"Conversion succeeded: {num}")
    finally:
        print("Cleanup complete")

    # Resource tracking
    class Resource:
        def __init__(self, name):
            self.name = name
            print(f"  Acquired: {name}")

        def close(self):
            print(f"  Released: {self.name}")

    print("\nResource management:")

    resource = None
    try:
        resource = Resource("Database")
        # Simulate work
        items = [1, 2, 3]
        value = items[5]  # Error!
    except IndexError:
        print("  Error during processing")
    finally:
        if resource:
            resource.close()

if __name__ == "__main__":
    main()
# Finally block for cleanup

def main():
    # Finally always executes
    print("Finally block basics:\n")

    try:
        print("In try block")
        result = 10 / 2
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("In except block")
    finally:
        print("In finally block (always runs)")

    # Finally runs even with exception
    print("\nWith exception:")

    try:
        print("In try block")
        result = 10 / 0  # raises error
        print("This won't print")
    except ZeroDivisionError:
        print("In except block")
    finally:
        print("In finally block (runs despite error)")


    # Simulated file handling
    def process_file(filename):
        file_handle = None
        try:
            print(f"\nOpening {filename}")
            file_handle = f"<handle:{filename}>"

            if "error" in filename:
                raise ValueError("Simulated read error")

            print(f"Processing {filename}")
            return "SUCCESS"

        except ValueError as e:
            print(f"Error: {e}")
            return "FAILED"
        finally:
            if file_handle:
                print(f"Closing {file_handle}")

    result1 = process_file("data.txt")
    print(f"Result: {result1}")

    result2 = process_file("error.txt")
    print(f"Result: {result2}")

    # Try-except-else-finally (complete form)
    print("\nComplete form:")

    value = "456"

    try:
        num = int(value)
    except ValueError:
        print("Conversion failed")
        num = 0
    else:
        # Runs only if NO exception
        print(f"Conversion succeeded: {num}")
    finally:
        print("Cleanup complete")

    # Resource tracking
    class Resource:
        def __init__(self, name):
            self.name = name
            print(f"  Acquired: {name}")

        def close(self):
            print(f"  Released: {self.name}")

    print("\nResource management:")

    resource = None
    try:
        resource = Resource("Database")
        # Simulate work
        items = [1, 2, 3]
        value = items[5]  # Error!
    except IndexError:
        print("  Error during processing")
    finally:
        if resource:
            resource.close()

if __name__ == "__main__":
    main()
# Finally block for cleanup

def main():
    # Finally always executes
    print("Finally block basics:\n")

    try:
        print("In try block")
        result = 10 / 2
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("In except block")
    finally:
        print("In finally block (always runs)")

    # Finally runs even with exception
    print("\nWith exception:")

    try:
        print("In try block")
        result = 10 / 0  # raises error
        print("This won't print")
    except ZeroDivisionError:
        print("In except block")
    finally:
        print("In finally block (runs despite error)")


    # Simulated file handling
    def process_file(filename):
        file_handle = None
        try:
            print(f"\nOpening {filename}")
            file_handle = f"<handle:{filename}>"

            if "error" in filename:
                raise ValueError("Simulated read error")

            print(f"Processing {filename}")
            return "SUCCESS"

        except ValueError as e:
            print(f"Error: {e}")
            return "FAILED"
        finally:
            if file_handle:
                print(f"Closing {file_handle}")

    result1 = process_file("data.txt")
    print(f"Result: {result1}")

    result2 = process_file("error.txt")
    print(f"Result: {result2}")

    # Try-except-else-finally (complete form)
    print("\nComplete form:")

    value = "abc"

    try:
        num = int(value)
    except ValueError:
        print("Conversion failed")
        num = 0
    else:
        # Runs only if NO exception
        print(f"Conversion succeeded: {num}")
    finally:
        print("Cleanup complete")

    # Resource tracking
    class Resource:
        def __init__(self, name):
            self.name = name
            print(f"  Acquired: {name}")

        def close(self):
            print(f"  Released: {self.name}")

    print("\nResource management:")

    resource = None
    try:
        resource = Resource("Database")
        # Simulate work
        items = [1, 2, 3]
        value = items[5]  # Error!
    except IndexError:
        print("  Error during processing")
    finally:
        if resource:
            resource.close()

if __name__ == "__main__":
    main()
  1. def main(): # Finally always executes

    3def main():4    # Finally always executes5    print("Finally block basics:\n")
    outputFinally block basics:
  2. result ← 5.0

    7try:8    print("In try block")9    result→ 5.0 = 10 / 210    print(f"Result: {result5.0}")11except ZeroDivisionError:
    outputIn try block
    Result: 5.0
  3. finally:

    11except ZeroDivisionError:12    print("In except block")13finally:14    print("In finally block (always runs)")1516# Finally runs even with exception
    outputIn finally block (always runs)
    In finally block (always runs)
  4. print(" With exception:")

    16# Finally runs even with exception17print("\nWith exception:")
    output
    With exception:
  5. try:

    19try:20    print("In try block")21    result = 10 / 0  # raises error22    print("This won't print")
    outputIn try block
  6. except ZeroDivisionError:

    22    print("This won't print")23except ZeroDivisionError:24    print("In except block")25finally:
    outputIn except block
  7. finally:

    23except ZeroDivisionError:24    print("In except block")25finally:26    print("In finally block (runs despite error)")2728#@help h1
    outputIn finally block (runs despite error)
    In finally block (runs despite error)
  8. result1 = process_file("data.txt")

    54result1 = process_file("data.txt")55print(f"Result: {result1}")
  9. file_handle ← None

    pass 1 of 2
    34# Simulated file handling35def process_file(filenamedata.txt):36    file_handle→ None = None37    try:
  10. file_handle ← <handle:data.txt>

    pass 1 of 2
    36file_handle = None37try:38    print(f"\nOpening {filenamedata.txt}")39    file_handle→ <handle:data.txt> = f"<handle:{filenamedata.txt}>"40    41    if "error" in filename:42        raise ValueError("Simulated read error")43    44    print(f"Processing {filenamedata.txt}")45    return "SUCCESS"
    output
    Opening data.txt
    Processing data.txt
  11. if file_handle:

    pass 1 of 2
    50finally:51    if file_handle<handle:data.txt>:52        print(f"Closing {file_handle<handle:data.txt>}")
    outputClosing <handle:data.txt>
    Closing <handle:data.txt>
  12. result1 ← SUCCESS

    54result1→ SUCCESS = process_file("data.txt")55print(f"Result: {result1SUCCESS}")5657result2 = process_file("error.txt")58print(f"Result: {result2}")
    outputResult: SUCCESS
  13. file_handle ← None

    pass 2 of 2
    34# Simulated file handling35def process_file(filenameerror.txt):36    file_handle→ None = None37    try:
  14. file_handle ← <handle:error.txt>

    pass 2 of 2
    36file_handle = None37try:38    print(f"\nOpening {filenameerror.txt}")39    file_handle→ <handle:error.txt> = f"<handle:{filenameerror.txt}>"
    output
    Opening error.txt
  15. if "error" in filename:

    41if "error" in filenameerror.txt:42    raise ValueError("Simulated read error")
  16. except ValueError as e:

    47except ValueError as e:48    print(f"Error: {eSimulated read error}")49    return "FAILED"50finally:
    outputError: Simulated read error
  17. if file_handle:

    pass 2 of 2
    50finally:51    if file_handle<handle:error.txt>:52        print(f"Closing {file_handle<handle:error.txt>}")
    outputClosing <handle:error.txt>
    Closing <handle:error.txt>
  18. result2 ← FAILED, value ← 123

    57result2→ FAILED = process_file("error.txt")58print(f"Result: {result2FAILED}")5960# Try-except-else-finally (complete form)61print("\nComplete form:")6263value→ 123 = "123"64#@value="456", "abc"
    outputResult: FAILED
    
    Complete form:
  19. num ← 123

    66try:67    num→ 123 = int(value123)68except ValueError:
  20. else: # Runs only if NO exception

    69    print("Conversion failed")70    num = 071else:72    # Runs only if NO exception73    print(f"Conversion succeeded: {num123}")74finally:
    outputConversion succeeded: 123
  21. finally:

    72    # Runs only if NO exception73    print(f"Conversion succeeded: {num}")74finally:75    print("Cleanup complete")7677# Resource tracking
    outputCleanup complete
    Cleanup complete
  22. resource ← None

    77# Resource tracking78class Resource:79    def __init__(self, name):80        self.name = name81        print(f"  Acquired: {name}")82    83    def close(self):84        print(f"  Released: {self.name}")8586print("\nResource management:")8788resource→ None = None89try:
    output
    Resource management:
  23. self.name ← Database

    78class Resource:79    def __init__(self<__main__.main.<locals>.Resource object at ⟨addr A⟩>, nameDatabase):80        self.name→ Database = nameDatabase81        print(f"  Acquired: {nameDatabase}")
    output  Acquired: Database
  24. resource ← <__main__.main.<locals>.Resource object at ⟨addr A⟩>

    89try:90    resource→ <__main__.main.<locals>.Resource object at ⟨addr A⟩> = Resource("Database")91    # Simulate work92    items→ [1, 2, 3] = [1, 2, 3]93    value = items[5](empty)  # Error!94except IndexError:
  25. except IndexError:

    93    value = items[5]  # Error!94except IndexError:95    print("  Error during processing")96finally:
    output  Error during processing
  26. if resource:

    96finally:97    if resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>:98        resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>.close()
  27. def close(self):

    83def close(self<__main__.main.<locals>.Resource object at ⟨addr A⟩>):84    print(f"  Released: {self.nameDatabase}")
    output  Released: Database
  28. resource.close()

    97if resource:98    resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>.close()
  29. main()

    100if __name__ == "__main__":101    main()
  1. def main(): # Finally always executes

    3def main():4    # Finally always executes5    print("Finally block basics:\n")
    outputFinally block basics:
  2. result ← 5.0

    7try:8    print("In try block")9    result→ 5.0 = 10 / 210    print(f"Result: {result5.0}")11except ZeroDivisionError:
    outputIn try block
    Result: 5.0
  3. finally:

    11except ZeroDivisionError:12    print("In except block")13finally:14    print("In finally block (always runs)")1516# Finally runs even with exception
    outputIn finally block (always runs)
    In finally block (always runs)
  4. print(" With exception:")

    16# Finally runs even with exception17print("\nWith exception:")
    output
    With exception:
  5. try:

    19try:20    print("In try block")21    result = 10 / 0  # raises error22    print("This won't print")
    outputIn try block
  6. except ZeroDivisionError:

    22    print("This won't print")23except ZeroDivisionError:24    print("In except block")25finally:
    outputIn except block
  7. finally:

    23except ZeroDivisionError:24    print("In except block")25finally:26    print("In finally block (runs despite error)")27
    outputIn finally block (runs despite error)
    In finally block (runs despite error)
  8. result1 = process_file("data.txt")

    49result1 = process_file("data.txt")50print(f"Result: {result1}")
  9. file_handle ← None

    pass 1 of 2
    29# Simulated file handling30def process_file(filenamedata.txt):31    file_handle→ None = None32    try:
  10. file_handle ← <handle:data.txt>

    pass 1 of 2
    31file_handle = None32try:33    print(f"\nOpening {filenamedata.txt}")34    file_handle→ <handle:data.txt> = f"<handle:{filenamedata.txt}>"35    36    if "error" in filename:37        raise ValueError("Simulated read error")38    39    print(f"Processing {filenamedata.txt}")40    return "SUCCESS"
    output
    Opening data.txt
    Processing data.txt
  11. if file_handle:

    pass 1 of 2
    45finally:46    if file_handle<handle:data.txt>:47        print(f"Closing {file_handle<handle:data.txt>}")
    outputClosing <handle:data.txt>
    Closing <handle:data.txt>
  12. result1 ← SUCCESS

    49result1→ SUCCESS = process_file("data.txt")50print(f"Result: {result1SUCCESS}")5152result2 = process_file("error.txt")53print(f"Result: {result2}")
    outputResult: SUCCESS
  13. file_handle ← None

    pass 2 of 2
    29# Simulated file handling30def process_file(filenameerror.txt):31    file_handle→ None = None32    try:
  14. file_handle ← <handle:error.txt>

    pass 2 of 2
    31file_handle = None32try:33    print(f"\nOpening {filenameerror.txt}")34    file_handle→ <handle:error.txt> = f"<handle:{filenameerror.txt}>"
    output
    Opening error.txt
  15. if "error" in filename:

    36if "error" in filenameerror.txt:37    raise ValueError("Simulated read error")
  16. except ValueError as e:

    42except ValueError as e:43    print(f"Error: {eSimulated read error}")44    return "FAILED"45finally:
    outputError: Simulated read error
  17. if file_handle:

    pass 2 of 2
    45finally:46    if file_handle<handle:error.txt>:47        print(f"Closing {file_handle<handle:error.txt>}")
    outputClosing <handle:error.txt>
    Closing <handle:error.txt>
  18. result2 ← FAILED, value ← 456

    52result2→ FAILED = process_file("error.txt")53print(f"Result: {result2FAILED}")5455# Try-except-else-finally (complete form)56print("\nComplete form:")5758value→ 456 = "456"
    outputResult: FAILED
    
    Complete form:
  19. num ← 456

    60try:61    num→ 456 = int(value456)62except ValueError:
  20. else: # Runs only if NO exception

    63    print("Conversion failed")64    num = 065else:66    # Runs only if NO exception67    print(f"Conversion succeeded: {num456}")68finally:
    outputConversion succeeded: 456
  21. finally:

    66    # Runs only if NO exception67    print(f"Conversion succeeded: {num}")68finally:69    print("Cleanup complete")7071# Resource tracking
    outputCleanup complete
    Cleanup complete
  22. resource ← None

    71# Resource tracking72class Resource:73    def __init__(self, name):74        self.name = name75        print(f"  Acquired: {name}")76    77    def close(self):78        print(f"  Released: {self.name}")7980print("\nResource management:")8182resource→ None = None83try:
    output
    Resource management:
  23. self.name ← Database

    72class Resource:73    def __init__(self<__main__.main.<locals>.Resource object at ⟨addr A⟩>, nameDatabase):74        self.name→ Database = nameDatabase75        print(f"  Acquired: {nameDatabase}")
    output  Acquired: Database
  24. resource ← <__main__.main.<locals>.Resource object at ⟨addr A⟩>

    83try:84    resource→ <__main__.main.<locals>.Resource object at ⟨addr A⟩> = Resource("Database")85    # Simulate work86    items→ [1, 2, 3] = [1, 2, 3]87    value = items[5](empty)  # Error!88except IndexError:
  25. except IndexError:

    87    value = items[5]  # Error!88except IndexError:89    print("  Error during processing")90finally:
    output  Error during processing
  26. if resource:

    90finally:91    if resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>:92        resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>.close()
  27. def close(self):

    77def close(self<__main__.main.<locals>.Resource object at ⟨addr A⟩>):78    print(f"  Released: {self.nameDatabase}")
    output  Released: Database
  28. resource.close()

    91if resource:92    resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>.close()
  29. main()

    94if __name__ == "__main__":95    main()
  1. def main(): # Finally always executes

    3def main():4    # Finally always executes5    print("Finally block basics:\n")
    outputFinally block basics:
  2. result ← 5.0

    7try:8    print("In try block")9    result→ 5.0 = 10 / 210    print(f"Result: {result5.0}")11except ZeroDivisionError:
    outputIn try block
    Result: 5.0
  3. finally:

    11except ZeroDivisionError:12    print("In except block")13finally:14    print("In finally block (always runs)")1516# Finally runs even with exception
    outputIn finally block (always runs)
    In finally block (always runs)
  4. print(" With exception:")

    16# Finally runs even with exception17print("\nWith exception:")
    output
    With exception:
  5. try:

    19try:20    print("In try block")21    result = 10 / 0  # raises error22    print("This won't print")
    outputIn try block
  6. except ZeroDivisionError:

    22    print("This won't print")23except ZeroDivisionError:24    print("In except block")25finally:
    outputIn except block
  7. finally:

    23except ZeroDivisionError:24    print("In except block")25finally:26    print("In finally block (runs despite error)")27
    outputIn finally block (runs despite error)
    In finally block (runs despite error)
  8. result1 = process_file("data.txt")

    49result1 = process_file("data.txt")50print(f"Result: {result1}")
  9. file_handle ← None

    pass 1 of 2
    29# Simulated file handling30def process_file(filenamedata.txt):31    file_handle→ None = None32    try:
  10. file_handle ← <handle:data.txt>

    pass 1 of 2
    31file_handle = None32try:33    print(f"\nOpening {filenamedata.txt}")34    file_handle→ <handle:data.txt> = f"<handle:{filenamedata.txt}>"35    36    if "error" in filename:37        raise ValueError("Simulated read error")38    39    print(f"Processing {filenamedata.txt}")40    return "SUCCESS"
    output
    Opening data.txt
    Processing data.txt
  11. if file_handle:

    pass 1 of 2
    45finally:46    if file_handle<handle:data.txt>:47        print(f"Closing {file_handle<handle:data.txt>}")
    outputClosing <handle:data.txt>
    Closing <handle:data.txt>
  12. result1 ← SUCCESS

    49result1→ SUCCESS = process_file("data.txt")50print(f"Result: {result1SUCCESS}")5152result2 = process_file("error.txt")53print(f"Result: {result2}")
    outputResult: SUCCESS
  13. file_handle ← None

    pass 2 of 2
    29# Simulated file handling30def process_file(filenameerror.txt):31    file_handle→ None = None32    try:
  14. file_handle ← <handle:error.txt>

    pass 2 of 2
    31file_handle = None32try:33    print(f"\nOpening {filenameerror.txt}")34    file_handle→ <handle:error.txt> = f"<handle:{filenameerror.txt}>"
    output
    Opening error.txt
  15. if "error" in filename:

    36if "error" in filenameerror.txt:37    raise ValueError("Simulated read error")
  16. except ValueError as e:

    42except ValueError as e:43    print(f"Error: {eSimulated read error}")44    return "FAILED"45finally:
    outputError: Simulated read error
  17. if file_handle:

    pass 2 of 2
    45finally:46    if file_handle<handle:error.txt>:47        print(f"Closing {file_handle<handle:error.txt>}")
    outputClosing <handle:error.txt>
    Closing <handle:error.txt>
  18. result2 ← FAILED, value ← abc

    52result2→ FAILED = process_file("error.txt")53print(f"Result: {result2FAILED}")5455# Try-except-else-finally (complete form)56print("\nComplete form:")5758value→ abc = "abc"
    outputResult: FAILED
    
    Complete form:
  19. try:

    60try:61    num = int(valueabc)62except ValueError:
  20. num ← 0

    61    num = int(value)62except ValueError:63    print("Conversion failed")64    num→ 0 = 065else:
    outputConversion failed
  21. finally:

    66    # Runs only if NO exception67    print(f"Conversion succeeded: {num}")68finally:69    print("Cleanup complete")7071# Resource tracking
    outputCleanup complete
    Cleanup complete
  22. resource ← None

    71# Resource tracking72class Resource:73    def __init__(self, name):74        self.name = name75        print(f"  Acquired: {name}")76    77    def close(self):78        print(f"  Released: {self.name}")7980print("\nResource management:")8182resource→ None = None83try:
    output
    Resource management:
  23. self.name ← Database

    72class Resource:73    def __init__(self<__main__.main.<locals>.Resource object at ⟨addr A⟩>, nameDatabase):74        self.name→ Database = nameDatabase75        print(f"  Acquired: {nameDatabase}")
    output  Acquired: Database
  24. resource ← <__main__.main.<locals>.Resource object at ⟨addr A⟩>

    83try:84    resource→ <__main__.main.<locals>.Resource object at ⟨addr A⟩> = Resource("Database")85    # Simulate work86    items→ [1, 2, 3] = [1, 2, 3]87    value = items[5](empty)  # Error!88except IndexError:
  25. except IndexError:

    87    value = items[5]  # Error!88except IndexError:89    print("  Error during processing")90finally:
    output  Error during processing
  26. if resource:

    90finally:91    if resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>:92        resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>.close()
  27. def close(self):

    77def close(self<__main__.main.<locals>.Resource object at ⟨addr A⟩>):78    print(f"  Released: {self.nameDatabase}")
    output  Released: Database
  28. resource.close()

    91if resource:92    resource<__main__.main.<locals>.Resource object at ⟨addr A⟩>.close()
  29. main()

    94if __name__ == "__main__":95    main()

finally: runs whether exception occurred or not. Good for cleanup.

finally Cleanup code that always runs. Close files, release resources.

Exercise: practical.py

Build a robust input parser with complete exception handling