Question presented to candidate: "Say you are writing a payments library. How would you design its exceptions, and when one of your functions catches a low-level error like a ValueError, how do you raise your own error without losing the original one?"
What a strong answer should cover:
- Subclass
Exception(notBaseException), give the library one base class so callers can catch everything with one clause, and add specific subclasses for errors callers handle differently - Extra data goes in attributes set in
__init__, with every argument passed on tosuper().__init__soargs,str()and pickling keep working; override__str__only for the message raise New(...) from originalsets__cause__(explicit chaining); raising inside anexceptblock sets__context__automatically (implicit chaining); the traceback wording differsraise New(...) from Nonesets__suppress_context__so the internal error is hidden from the traceback but still kept on__context__add_note()(3.11+, PEP 678) attaches extra context to an exception after it was raised- Chaining dates from PEP 3134 (Python 3.0) and
from Nonefrom PEP 415 (3.3)
Clarifying questions expected:
- Who catches these errors: application code, an HTTP layer that maps them to status codes, or both?
- Do the errors need to cross process boundaries (multiprocessing, task queues), which requires pickling?
Code / implementation expected: Yes β a small hierarchy with one attribute-carrying subclass, and a function that translates a built-in error with raise ... from e.