Exceptions in python as class attributes bad?

I often find that I want to structure my exception classes as follows:

# legends.py class Error(Exception): pass class Rick(object): class Error(Error): pass class GaveYouUp(Error): pass class LetYouDown(Error): pass class Michael(object): class Error(Error): pass class BlamedItOnTheSunshine(Error): pass class BlamedItOnTheMoonlight(Error): pass 

I only saw this template used in Django ( DoesNotExist ), and it makes that sense. Is there something I'm missing, why do most people prefer top-notch exceptions?

edit I would use these classes for universal granularity, for example:

 import legends try: do_stuff() except legends.Michael.Error: blame_it_on_the_boogie() except legends.Rick.GaveYouUp: let_you_down() except legends.Error: pass except Exception as e: raise Hell() 
+7
source share
2 answers

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.

+9
source

If you want to raise, for example, BlamedItOnTheSunshine outside Micheal you will have to call it raising Micheal.BlamedItOnTheSunshine ("error text").

eg:.

 class A: class E(Exception): pass def __init__(self): raise A('error in A') class B: def __init__(self): raise AE('error in B') 

in this example, A and B are not related, but if you have a relationship like:

 class Interpret(object): class LetsYouDown(Exception): pass def __init__(self): raise self.LetsYouDown("I'm not Rick!") class Michael(Interpret): class BlameItOnTheSunshine(Exception): pass def __init__(self): raise self.BlameItOnTheSunshine("It not the Moon!") class Rick(Interpret): class NeverEver(Exception): pass def __init__(self): print "Never Ever!" and want now something like: try: for superstar in [Interpret, Michael, Rick]: star_in_show = superstar() except superstar.LetsYouDown: print "Where Rick?" except superstar.BlameItOnTheSunshine: print "Must be Michael!" 

you get an error, I would call a violation of the Liskov principle. Therefore, one of the main reasons (polymorphism) for using OOP is somewhat compromised. But this does not necessarily mean that you cannot or should not use it. Just keep in mind the limitations.

I hope I cleared my initial critical reservations.

+1
source

All Articles