Best practise hierarchy for user-defined exceptions

Slaunger Slaunger at gmail.com
Mon Nov 17 08:23:38 EST 2008


On 17 Nov., 13:05, "Chris Rebert" <c... at rebertia.com> wrote:
> On Mon, Nov 17, 2008 at 3:47 AM, Slaunger <Slaun... at gmail.com> wrote:
>
> > .....
> > Here is my stub-implemented idea on how to do it so far, which is
> > inspired by how I would have done it in Java (but which may not be
> > very Pythonic??):
>
> > class MyException(Exception):
>
> >    pass
>
> The above class probably isn't necessary. You don't need to
> overgeneralize this much.
>
Seems reasonable.
> > class MyStandardError(MyException, StandardError):
>
> >    pass
>
> Rename the previous class to just MyError in light of removing the other class.
>
>
OK.
>
> > class MyParseError(MyStandardError, ValueError):
>
> >   pass
>
> This technique is very Pythonic. Subclass from both the exception
> class for your module and from a built-in one if there's an applicable
> one.
>
>
OK. One thing I *like* about it is that I inherit properties of
ValueError.

One thing I feel *a little uneasy about* is that if I do something
like this

try:
    do_something_which_raises_MyParseError_which_I_have_overlooked()
    do_something_where_I_know_a_ValueError_can_be_raised()
catch ValueError:
    handle_the_anticipated_ValueError_from_std_lib()
finally:
    ....

I will not notice that it was an unanticpated condition in my own
code, which caused the ValueError
to be raised. If I had just inherited from MyError, it would fall
through (which I would prefer)

Once I had seen a trace back to the unanticipated MyParseError I would
of course correct the code to

try:
    do_something_where_I_now_know_MyParseError_can_be_raised()
    do_something_where_I_know_a_ValueError_can_be_raised()
catch MyParseError:
    handle_the_anticipated_MyParseError_generated_in_own_code()
catch ValueError:
    handle_the_anticipated_ValueError_from_std_lib()
finally:
    ....

Is the above multiple catch methology pythonic as well?

On the other hand, with multiple inheritance this works:

try:
    do_something_where_I_know_a_MyParseError_can_be_raised()
    do_something_where_I_know_a_ValueError_can_be_raised()
catch ValueError:
    handle_a_MyParseError_or_a_ValueError_in_the_same_manner()
finally:
    ....

which is nice is you are very aware that MyParseError descends from
ValueError (which may not be self-evident)


>
> > Some comments and questions
>
> > 1. The hierarchy is deliberately deep and maps to the std library such
> > that it is easier to extend
>
> Zen of Python: Flat is better than nested.
> This is part of the reason I recommend removing the one class.

Ah, OK, have to adjust my mindset a little. Willing to accomodate
though... ;-)
>
> > 3. I use multiple inheritance in the two sub-classes. I have not tried
> > that before. Is this A Good Thing or A Bad Thing to do?
>
> Good in this case, just be careful to use super() if you override any methods.

I will!

>
> > 4. Which __xx__ methods would you normally implement for the user-
> > defined exception classes? I was thinking of __str__, for example? Is
> > there a recommended __str__ idiom to use for that?
>
> You might override __init__ if you want to store additional
> information about the cause of the exception (e.g. location of parse
> error, name of the rule the error occurred in, etc).
> The __str__ inherited from Exception is usually sufficient, but you
> can override it if you want to. it's a judgement call IMHO.
>

OK. Seems pretty straight-forward. I like Python more and more.

> Cheers,
> Chris

That was a very useful answer. Thank you, Chris for taking your time
to reply on my questions.

Cheers,
-- Slaunger



More information about the Python-list mailing list