BaseException
Every exception inherits args, tracebacks, chaining and notes from here — but your own exceptions should subclass Exception, not this.
Demo
e = BaseException(*['disk full']) (e.args, str(e))
In Raise, watch str(e) change shape: one argument prints as itself, two print as the repr of the whole tuple, none prints as an empty string. In Handle, KeyboardInterrupt, SystemExit and GeneratorExit all fall through except Exception — that is exactly why they inherit from BaseException. Type an unknown name and the KeyError from the dict lookup is caught by except Exception instead.
Constructor
| Name | Type | Required | Description |
|---|---|---|---|
| *args | object | no | Any positional arguments, stored unchanged in e.args. Keyword arguments are rejected: BaseException() takes no keyword arguments. |
Attributes
| Attribute | Type | Meaning |
|---|---|---|
| args | tuple | The positional constructor arguments, unchanged. str(e) is built from it. |
| __traceback__ | traceback | None | The traceback object; None until the exception is raised. Writable. |
| __cause__ | BaseException | None | Explicit chaining — set by raise NewError(...) from original. |
| __context__ | BaseException | None | Implicit chaining — the exception that was being handled when this one was raised. Set automatically. |
| __suppress_context__ | bool | True after raise ... from ... (including from None): the traceback then hides __context__. |
| __notes__ | list[str] | Extra lines shown after the message in the traceback. Created by the first add_note() call (3.11+). |
| add_note(note) | method | Append a string to __notes__. A non-string raises TypeError. (3.11+) |
| with_traceback(tb) | method | Set __traceback__ to tb and return the same exception object. |
Common patterns
try: run() except Exception as e: log.error('run failed: %r', e)
try: cfg = json.loads(text) except ValueError as e: raise ConfigError('config.json is not valid JSON') from e
for n, line in enumerate(lines, 1): try: parse(line) except ValueError as e: e.add_note(f'line {n}: {line!r}') raise
try: work() except BaseException: rollback() raise
Examples
Pitfalls
import sys def main(): try: sys.exit(2) except: return 'kept running' main()
import sys def main(): try: sys.exit(2) except Exception: return 'kept running' try: main() except SystemExit as e: r = f'exiting with status {e.code}' r
class AppError(BaseException): pass try: try: raise AppError('db down') except Exception: r = 'handled' except BaseException as e: r = f'escaped: {e!r}' r
class AppError(Exception): pass try: try: raise AppError('db down') except Exception: r = 'handled' except BaseException as e: r = f'escaped: {e!r}' r
try: raise TimeoutError except Exception as e: msg = f'failed: {e}' msg
try: raise TimeoutError except Exception as e: msg = f'failed: {e!r}' msg
When to use
- Reading the shared attributes: args, __cause__, __context__, __notes__, __traceback__
- except BaseException: only to clean up and re-raise
- Type hints for code that accepts any exception object (loggers, reporters)
- Base class for your own errors → subclass Exception
- Catch-all error handling → except Exception
- Bare except: — it is except BaseException in disguise
Notes
FAQ
A bare except: catches everything derived from BaseException — including KeyboardInterrupt (Ctrl+C), SystemExit (sys.exit()) and GeneratorExit. except Exception catches only ordinary errors and lets those three through, so the program can still be interrupted and can still exit. Use except Exception for catch-all handling; use a bare except or except BaseException only when you re-raise.