[Tutor] Subclassing Exceptions

Chris Fuller cfuller at thinkingplanet.net
Sat Jan 7 06:16:51 CET 2012


On Friday 06 January 2012, Steven D'Aprano wrote:
> Chris Fuller wrote:
> >>>> class Foo(SyntaxError):
> > ...  def __init__(self, a,b,c):
> > ...   self.args = (a,b,c)
> > ...
> > 
> >>>> raise Foo(1,2,3)
> > 
> > Traceback (most recent call last):
> >   File "<stdin>", line 1, in <module>
> > 
> > __main__.Foo: None
> > 
> > 
> > Inheriting from SyntaxError doesn't work!  When I create a new exception,
> > I generally subclass from the built-in exception it most resembles, in
> > case there was some reason to also catch it via an ancestor.  But I'm
> > not sure if that is really all that useful an idea in practice.  How do
> > you folk do it?
> 
> What do you mean, "doesn't work"? It looks like it works to me. You get a
> Foo exception, exactly as expected. The error message isn't what you
> expect, because you're making unwarranted assumptions about SyntaxError
> and how it works.
> 
> In general, when you override a method, you take full responsibility to
> perform everything that the superclass method was supposed to do. In this
> case, you fail to assign to msg as well as args. It is safer to overload a
> 
> message rather than override it:
>  >>> class Spam(SyntaxError):
> ...     def __init__(self, *args):
> ...             if args:
> ...                     args  = ("I pity the fool who made a mistake",) +
> args[1:] ...             super(Spam, self).__init__(*args)
> ...
> 
>  >>> raise Spam('you made a mistake', 1, 2)
> 
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
> __main__.Spam: I pity the fool who made a mistake
> 
> 
> 
> Unfortunately, there's no real consistency in what arguments exceptions are
> expected to take. The best thing is to read the docs, if they have any, or
> use introspection and trial and error to work out what they do.
> 
>  >>> try:
> ...     raise SyntaxError("you made a mistake")
> ... except SyntaxError, err:
> ...     pass
> ...
> 
>  >>> err.msg
> 
> 'you made a mistake'
> 
> 
> See dir(err) for more; you can use help(SyntaxError) but unfortunately it
> isn't very useful.
> 
> 
> You probably shouldn't inherit from SyntaxError, since it represents syntax
> errors in the Python code being interpreted or compiled. Any syntax error
> in your own data structures should be independent of SyntaxError.

In "Python: Essential Reference", David Beazley recommends that the parameters 
of the exception be assigned to the args attribute, so it is passed all the 
way through the traceback.  You will observe that the last element in the 
traceback loses this information when subclassed from SyntaxError.  This isn't 
a problem when the whole traceback is laid out before you, but can come into 
play with automated tools that catch/log/manipulate exceptions.  This behavior 
of exceptions isn't apparently mentioned in the canonical documentation, 
however.

I had the same thought about not wanting to mix syntax errors in the data with 
syntax errors in the code, but that applies to any exception, really.  In 
fact, it's better to inherit from a more derived class, because when you catch 
an ancestor, you'll be grabbing less greedily at the possible coding errors.  
Which suggests that giving a damn about built-in ancestors of user-defined 
exceptions is a losing proposition, now that I think about it.

Cheers


More information about the Tutor mailing list