Skip to lesson content

PYTHON / LESSON 12 OF 18

Exception handling

Read the explanations, work through the examples, and complete the student tasks.

Learning goals

Handle expected failures, raise clear validation errors, and read tracebacks.

Explanation

An exception signals a runtime failure. try surrounds work that may fail. An except clause handles a matching exception. else runs if the try block finishes without an exception; finally runs when control leaves the statement, including normal exception propagation. It is useful for cleanup, though with is preferable for files.

Common exceptions include ValueError for an unacceptable value, TypeError for an inappropriate type, ZeroDivisionError, FileNotFoundError, KeyError, and IndexError. Read the final traceback line for the error type and message, then follow the frames to your own code.

Example 1 A guarded calculation

for text in ["2", "0", "two"]:
    try:
        divisor = int(text)
        result = 10 / divisor
    except ValueError:
        print("Enter a whole number")
    except ZeroDivisionError:
        print("Divisor cannot be zero")
    else:
        print("Result:", result)
    finally:
        print("Attempt complete")

Expected output:

Result: 5.0
Attempt complete
Divisor cannot be zero
Attempt complete
Enter a whole number
Attempt complete

Each iteration continues because both expected failures are handled. Catching a specific exception tells readers what failure you anticipated.

Example 2 Domain validation with a custom exception

class InvalidScoreError(ValueError):
    pass

def validate_score(score):
    if not 0 <= score <= 100:
        raise InvalidScoreError("Score must be between 0 and 100")
    return score

for score in [85, -5]:
    try:
        print("Valid:", validate_score(score))
    except InvalidScoreError as error:
        print("Rejected:", error)

Expected output: Valid: 85, then Rejected: Score must be between 0 and 100. The function enforces a rule; its caller decides how to report the problem. Subclassing ValueError lets callers catch either the specific domain error or the broader category.

Common mistakes

except: pass hides errors and makes debugging difficult. Do not wrap the entire application in one broad handler. Keep try blocks close to the operation you expect to fail. Avoid return in finally because it can override a return value or suppress an exception. Log unexpected failures with useful context instead of pretending the operation succeeded.

Student tasks

1. Ask repeatedly for a whole number until valid input is supplied. Test blank text, "abc", and "12".

2. Read a nonexistent practice file and display a friendly FileNotFoundError message.

3. Write validate_age that rejects negative values using ValueError.

4. Trigger an IndexError in a separate tiny script, record the traceback, and fix the incorrect index.

Completion check: catch specific exceptions and demonstrate both successful and failing inputs.