1.3.6 · D1Python Intermediate

Foundations — Raising exceptions — raise, custom exception classes

1,383 words6 min readBack to topic

The parent note uses a lot of small pieces of machinery — objects, classes, __init__, super(), the call stack, tracebacks, inheritance — as if you already own them. This page builds each one from zero, in the order they stack on top of each other. Read top to bottom: nothing appears before it is earned.


1. A "value" and a "return" — the normal case

Picture it. A function is a vending machine: you put in a request, it drops out a can (the return value). Look at the figure — the green can is the answer travelling back down.

Why the topic needs it: the entire reason raise exists is the situation where there is no honest can to drop. You can't understand "no answer possible" until you understand "answer possible".


2. The call stack — who called whom

Picture it. Think of stacked plates. You can only add or remove from the top. When a finishes, its plate is removed and we're back inside b.

Why the topic needs it: the parent says an exception "propagates up the call stack." "Up" means from the top plate (a) toward the bottom plate (c) — removing plates that don't handle it. Without the stack picture, "up" is meaningless.


3. An object and a class — the shape of an exception

This is exactly why the parent says:

raise ValueError passes the class (drawing); Python builds a house for you. raise ValueError("x") passes an instance (house you built yourself, painted with the message).

See Classes and __init__ for the full construction story.


4. __init__, self, and super() — building a house with details

Read the parent's custom exception again, now decoded:

class InsufficientFundsError(Exception):
    def __init__(self, balance, requested):
        self.balance = balance            # store data ON this object
        self.requested = requested
        self.shortfall = requested - balance
        super().__init__(                 # let the PARENT store the message
            f"Tried {requested}, only {balance} available."
        )

5. Inheritance and the hierarchy — "is-a"

Why the topic needs it: except Exception: catches everything under Exception (the green subtree) but deliberately not the Ctrl-C signal. That is exactly why the parent insists: inherit from Exception, never BaseException. Full map in Exception Hierarchy & BaseException.


6. Traceback — the breadcrumb trail

Picture it. As the alarm rises through the stack of plates, it staples a note to each plate it leaves. When it reaches the top and nobody catches it, Python reads all the stapled notes to you.

Why the topic needs it: a bare raise re-throws keeping the same staples (original traceback). raise B from A staples a note that says "A caused B." You cannot appreciate either without the traceback picture.


7. The one core mechanism, assembled

Now every symbol is earned, here is the whole raise flow using only defined words: build an instance of an exception class, attach a traceback, then walk up the call stack frame by frame, popping frames that have no matching except, until one catches it or it exits at the bottom.

value and return

call stack and frames

class and object

init self super

inheritance Exception vs BaseException

raise and propagation

traceback

Raising exceptions custom classes

Related lighter tools: assert statement raises AssertionError for you, and Logging in Python powers the log-and-re-raise pattern. Catching happens in Try-Except-Finally. This all supports the parent Raising exceptions.


Equipment checklist

  • What does return do, and how is it different from raising? ::: return hands a value back down to the caller; raising throws an alarm object up when no honest value exists.
  • What is a frame and what is the call stack? ::: A frame is the memory of one running function; the call stack is those frames stacked, with the running one on top.
  • Class vs instance? ::: A class is the blueprint (ValueError); an instance is a concrete object built from it (ValueError("x")).
  • What is self inside __init__? ::: The specific object currently being built, onto which you store attributes.
  • Why call super().__init__(message)? ::: So the parent Exception stores the message in .args, making str(e) print it.
  • What does class B(A) mean? ::: B is-a kind of A and inherits A's abilities.
  • Why inherit from Exception not BaseException? ::: BaseException also covers KeyboardInterrupt/SystemExit, which ordinary handling must not swallow.
  • What is a traceback? ::: The recorded trail of frames an exception passed through, printed for debugging.

Connections

  • Try-Except-Finally — where the thrown alarm gets caught
  • Exception Hierarchy & BaseException — the inheritance tree in full
  • Classes and __init__ — building objects and constructors
  • Logging in Python — the log-and-re-raise pattern
  • assert statement — a lighter cousin that raises for you