CodeMIRAI
0 XP

Raising your own exceptions

2 min read 5 runnable examples Quiz included

Your own functions can raise exceptions too. It's how a function says "I can't do what you asked, and here's why", instead of silently returning a wrong answer.

raise

Python
def set_age(age):
    if age < 0:
        raise ValueError(f"Age can't be negative (got {age})")
    print("Age set to", age)

set_age(30)
set_age(-5)

The function stops at raise, and the caller receives the exception, just like a built-in one.

Catching what you raise

Python
def withdraw(balance, amount):
    if amount <= 0:
        raise ValueError("Amount must be positive.")
    if amount > balance:
        raise ValueError(f"Insufficient funds: balance is {balance}.")
    return balance - amount

for amount in [50, -10, 500]:
    try:
        print("New balance:", withdraw(200, amount))
    except ValueError as e:
        print("Refused:", e)

Raising in the function and catching in the caller keeps the two jobs apart: the function detects the problem, the caller decides what to do about it.

Choosing the exception type

Pick the built-in exception that matches the problem:

  • ValueError for a bad value,
  • TypeError for the wrong type,
  • KeyError / IndexError for missing items,
  • RuntimeError when nothing else fits.

Your own exceptions

For errors specific to your program, define a class that inherits from Exception:

Python
class InsufficientFundsError(Exception):
    """Raised when a withdrawal is larger than the balance."""

def withdraw(balance, amount):
    if amount > balance:
        raise InsufficientFundsError(f"Need {amount - balance} more.")
    return balance - amount

try:
    withdraw(100, 180)
except InsufficientFundsError as e:
    print("Payment failed:", e)

Custom exceptions make except blocks precise: callers can catch exactly your error and nothing else.

Re-raising

Sometimes you want to note an error and still pass it on. A bare raise inside except re-raises the same exception:

Python
def load_setting(settings, key):
    try:
        return settings[key]
    except KeyError:
        print(f"[log] setting {key!r} is missing")
        raise

try:
    load_setting({"theme": "dark"}, "language")
except KeyError:
    print("The caller handled it.")

assert: checks for programmers

assert raises an AssertionError when a condition is false. It's for catching bugs during development, not for validating user input:

Python
def average(numbers):
    assert len(numbers) > 0, "average() needs at least one number"
    return sum(numbers) / len(numbers)

print(average([2, 4, 6]))
print(average([]))
Finished this lesson?Mark it complete to earn +20 XP and move your progress on.