Skip to content
Theory · Exceptions · lesson 6 of 11

raise

Until now, the boxes in our column cracked on their own: Python raised the exception when a division or int failed. Now a function will signal the break itself.

Picture a bank cashier. You ask to withdraw more than the account holds. The cashier does not silently hand you an empty envelope—you might not open it and walk away. The cashier refuses out loud, so the refusal cannot go unnoticed.

A function, too, cannot always do what it is asked to do. Returning a special value such as None in that case is unreliable—the calling code may not check it. The raise statement raises an exception, and the function reports the error the same way built-in ones do:

Python
def withdraw(balance, amount):
    if amount > balance:
        raise ValueError("not enough money")
    return balance - amount


print(withdraw(100, 30))  # 70
try:
    print(withdraw(100, 500))
except ValueError as e:
    print("error:", e)  # error: not enough money

Let's go step by step:

  1. withdraw(100, 30) passes the check and returns 70.
  2. withdraw(100, 500) sees that 500 is greater than 100 and runs raise.
  3. The function ends at once, and the exception goes to the try around the call.
  4. The except ValueError branch prints error: not enough money.

What goes after raise

After raise comes an exception. Only an instance of BaseException or of its descendant, or such a class itself, can be raised. There are two ways.

An object with a message

Most often you write a class with a message in parentheses: raise ValueError("not enough money"). Python creates the exception object, and the message later shows up in print(e) and in the last line of the traceback.

A class without parentheses

You can also write the class alone, raise ValueError. Then Python creates the object itself, with no message. This is rare: without a message, it is harder to see what went wrong.

The class is chosen by the meaning of the error:

  • ValueError for an unsuitable value;
  • TypeError for an unsuitable type.

The path of an exception

raise ends the function at once, like return, but an exception goes up instead of a value. It reaches the caller, then the caller's caller, and so on, until it meets a try with a fitting except. This is the same path up the column of boxes that Python's own exceptions take.

If there is no such try all the way to the top, the program stops with a traceback. Its last call points at the line with raise, and its last line repeats the class and the message. In the first example, withdraw(100, 500) returned no value, so the outer print never ran.

Here the cashier picture ends: a cashier refuses only the person standing in front of them. An exception goes higher, until someone on its path catches it.

Raising again

Sometimes an error needs to be noticed but not fully handled: print where it happened and pass it on. For this, write raise with no arguments inside except. This is a re-raise: the same exception goes up unchanged.

Python
def parse(text):
    try:
        return int(text)
    except ValueError:
        print("cannot read", text)  # cannot read x
        raise


try:
    parse("x")
except ValueError:
    print("caller caught it")  # caller caught it

Let's go step by step:

  1. int("x") in the parse function raises a ValueError.
  2. The except branch in parse prints cannot read x.
  3. raise with no arguments raises the same ValueError again, and parse ends.
  4. The try around the call catches the exception, and the program prints caller caught it.

Without the outer try, the program would stop with a traceback pointing at int(text). A re-raise keeps the original place of the error, which matters when you look for the cause.

Common mistake

A string is written after raise instead of an exception:

Python
def withdraw(balance, amount):
    if amount > balance:
        raise "not enough money"  # ✗
    return balance - amount


withdraw(100, 500)
TEXT
TypeError: exceptions must derive from BaseException

A string is not an exception: str is not a descendant of BaseException, so Python raises a TypeError instead. The message goes in the class's parentheses: raise ValueError("not enough money").

Key points

  • raise raises an exception and ends the function at once; an exception goes up instead of a value.
  • After raise comes an exception instance or class, usually with a message: raise ValueError("not enough money").
  • raise with no arguments inside except passes the same exception on unchanged.
  • A string after raise gives a TypeError: only a descendant of BaseException can be raised.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way