Python Essentials for AI Engineer

Course Content

Python Essentials for AI Engineer

6 sections · 48 lessons

What is raise in Python?


What you need to know

Raising with a good message

Python
def set_temperature(t):    if not isinstance(t, (int, float)):        raise TypeError(f"temperature must be a number, got {type(t).__name__}")    if not 0 <= t <= 2:        raise ValueError(f"temperature must be between 0 and 2, got {t}")    return tfor value in [0.7, 5, "hot"]:    try:        print(set_temperature(value))    except (TypeError, ValueError) as e:        print(type(e).__name__, "-", e)# 0.7# ValueError - temperature must be between 0 and 2, got 5# TypeError - temperature must be a number, got str

Pick the built-in type that fits: ValueError for a right type with a bad value, TypeError for the wrong type, KeyError/LookupError for a missing item, NotImplementedError for a method a subclass must provide, RuntimeError for "something went wrong" with no better class. Put the bad value in the message; it saves the reader a debugging session.

Re-raising and chaining

Python
import jsonclass ConfigError(Exception):    passdef load_config(text):    try:        cfg = json.loads(text)        return cfg["model"]    except KeyError as err:        raise ConfigError("config has no 'model' field") from err    except json.JSONDecodeError:        print("logging the bad config...")        raise                                  # same exception, original tracebacktry:    load_config('{"temperature": 0.2}')except ConfigError as e:    print(e, "| cause:", repr(e.__cause__))# config has no 'model' field | cause: KeyError('model')
  • Bare raise re-raises the exception being handled, unchanged.
  • raise X from err sets X.__cause__, and the traceback shows both, joined by "The above exception was the direct cause of the following exception".
  • If you raise inside an except without from, Python still links them, but the message reads "During handling of the above exception, another exception occurred" — which looks like a bug in your handler. from None hides the original when it adds nothing.
  • Python 3.11+ lets you attach extra context without changing the type: e.add_note(f"row {i}").

raise vs assert

assert x > 0 raises AssertionError, but asserts are removed when Python runs with -O. Use them for internal "this can't happen" checks, never for validating user input or API data.

A real-life example

A RAG service accepts top_k from a request. A client sends top_k=0. Without validation, the retriever returns an empty list, the prompt has no context, and the LLM answers from its own memory — a confident, ungrounded answer. No error appears anywhere, and the team finds out from a customer complaint.

With a guard at the edge — if top_k < 1: raise ValueError(f"top_k must be at least 1, got {top_k}") — the API returns a clear 400 error at once, and the client fixes their call. Raising early turns a silent quality bug into a visible input bug.

Follow-up questions to expect

  • "What is the difference between raise and raise e?" — Bare raise re-raises the current exception exactly as it was. raise e also works in Python 3 but adds the current line to the traceback; bare raise is the idiom.
  • "What is exception chaining?" — Linking a new exception to the one that caused it with raise ... from err, so the traceback shows both.
  • "Can you raise any object?" — No. Only instances or subclasses of BaseException; raise "error" is a TypeError.