This is the exact pattern used by Django for specific ORM exceptions.
The advantage is that you can have an except clause that checks the type that is accessed through the instance:
rick = Rick() try: rick.roll() except rick.GaveYouUp: never() except rick.LetYouDown: never_ever()
It doesn't look useful here, but if rick was a function parameter, then it would potentially be quite useful.
It is also extremely useful when writing generic code that raises exceptions:
GoddamStar(object): def sing(self,tune): raise self.Error() class Rick(GoddamStar): class Error(Error): pass class GaveYouUp(Error): pass class LetYouDown(Error): pass class Michael(GoddamStar): class Error(Error): pass class BlamedItOnTheSunshine(Error): pass class BlamedItOnTheMoonlight(Error): pass rick = Rick() try: rick.sing() except Rick.GaveYouUp: never() except Michael.Error: never_ever()
Django's exceptions are typically based on global base classes, so you can also have a catch-all clause that still includes an exception type, in case your rick has an unknown (or otherwise unsecured) class,
The reason this is not much more common is that (a) it does not work in the early languages ββthat attract most book authors (b) it is moderately rare, which is useful to the user, and therefore application developers probably consider that they will not be needed.
Marcin
source share