Define your own exception classes so errors carry a clear name and the data needed to handle them.
# define custom exception
class CustomError(Exception):
pass
# ans: raise it
raise CustomError("Something went wrong")
Inheriting from Exception is all it takes; pass keeps everything else from the parent.
# exception with data
class ValidationError(Exception):
def __init__(self, field, message):
self.field = field
self.message = message
super().__init__(f"{field}: {message}")
super().__init__(...) sets the text you see when the exception is printed.
# raise custom exception
try:
raise ValidationError("email", "Invalid format")
except ValidationError as e:
print(e.field)
print(e.message)
# base exception
class DatabaseError(Exception):
pass
# ans: specific exceptions
class ConnectionError(DatabaseError):
pass
class QueryError(DatabaseError):
pass
One base class lets callers catch every database problem with a single except DatabaseError. (This ConnectionError shadows Python's built-in one of the same name.)
raiseexceptAn except matches its own class and every class below it.
Predict, then reveal.
# inherit from what?
class MyError(Exception):
pass
# ans: inherits from Exception
# can inherit from BaseException?
class MyError(BaseException):
pass
# ans: yes, but use Exception instead
except Exception would not catch it, just like KeyboardInterrupt.
# custom message?
class MyError(Exception):
pass
raise MyError("Custom message")
# ans: works!
# catch custom exception?
try:
raise CustomError()
except CustomError:
print("Caught")
# ans: "Caught"
# exception with default message?
class MyError(Exception):
def __init__(self):
super().__init__("Default message")
raise MyError() now shows MyError: Default message.
# multiple custom exceptions?
class Error1(Exception):
pass
class Error2(Exception):
pass
try:
pass
except (Error1, Error2):
pass
A tuple in except catches any of the listed classes.
# exception hierarchy catch?
class Base(Exception):
pass
class Derived(Base):
pass
try:
raise Derived()
except Base:
print("Caught")
# ans: "Caught"
A Derived is a kind of Base, so except Base matches it.
# custom exception attributes?
class MyError(Exception):
def __init__(self, code):
self.code = code
Handlers can read e.code. Without super().__init__, the printed message is just the code.
# exception with __str__?
class MyError(Exception):
def __str__(self):
return "Custom string"
str(e) and the traceback now show Custom string.
# empty custom exception?
class MyError(Exception):
pass
# ans: valid minimal exception
ExceptionNot BaseException; a bare pass body is enough.
Store fields in __init__ and pass a message to super().__init__.
A base class per area lets callers catch broadly or narrowly.
except Parent catches every child class too.