Abstract Base Classes

B

Ben Finney

Howdy all,

Okay, so Guido doesn't like Abstract Base Classes[0], and interfaces
are the way of the future[1]. But they're not here now, and I
understand ABCs better.

I want my modules to (sometimes) define an abstract base exception
class, that all other exceptions in that module inherit from.

class FooException(Exception):
""" Base class for all FooModule exceptions """

class FooBadFilename(FooException):
""" Raised when a bad filename is used in a foo """

class FooUnknownBar(FooException, KeyError):
""" Raised when an unknown bar is used with a foo """

However, there should never be an exception raised of class
FooException, and in fact I want that to cause an appropriate error to
be raised from the module.

Normally, I'd pick some key part of the functionality of the class,
and cause that to raise NotImplementedError. It's then the
responsibility of subclasses to override that.

However, in the case of exceptions, I don't want to override *any*
functionality; everything should be provided by the base classes. It'd
be messy to have to override something in every subclass just to
ensure the abstraction of the module base exception.

I've tried doing this in the __init__():

class FooException(Exception):
""" Base class for all FooModule exceptions """
def __init__(self):
raise NotImplementedError, \
"%s is an abstract class for exceptions" % self.__class__

When I use this, I discovered to my horror that the subclasses were
calling FooException.__init__ -- which I though wasn't supposed to
happen in Python!

It's also rather semantically weird, to my eye.

Can I do something tricky with checking base classes in the
FooException.__init__() ?


[0] Although he's apparently been quoted earlier as saying he did.
He's changed his mind[1] since then.

[1] <URL:http://www.artima.com/weblogs/viewpost.jsp?thread=92662>
 
M

Mike Meyer

Ben Finney said:
I've tried doing this in the __init__():

class FooException(Exception):
""" Base class for all FooModule exceptions """
def __init__(self):
raise NotImplementedError, \
"%s is an abstract class for exceptions" % self.__class__

When I use this, I discovered to my horror that the subclasses were
calling FooException.__init__ -- which I though wasn't supposed to
happen in Python!
It's also rather semantically weird, to my eye.

Calling __init__ is handled just like any other method (this is a good
thing), so if your subclasses fail to define __init__, the version in
the superclass gets called. If it were otherwise, every class would
have to declare __init__ just to call super(cls, self).__init__.
Can I do something tricky with checking base classes in the
FooException.__init__() ?

Untested:

class FooException(Exception):
def __init__(self):
if self.__class__ == FooException:
raise NotImplementedError,
"FooException is an abstract class for exceptions"

Personally, I find this unpythonic. FooException doesn't contribute
anything, and has no real reason for existing. If Python did static
type checking, it would make sense, but python doesn't, so it doesn't.

If you hadn't referenced interfaces, I'd suspect you might be planing
on catching all FooExceptions in a try:/except:. I'm not sure you'll
be able to list an interace in an except clause when they come to
exist, though.

<mike
 
B

Ben Finney

Mike Meyer said:
class FooException(Exception):
def __init__(self):
if self.__class__ == FooException:
raise NotImplementedError,
"FooException is an abstract class for exceptions"

Shall try this when I get the chance. Thanks.
Personally, I find this unpythonic. FooException doesn't contribute
anything, and has no real reason for existing.

The purpose is to be able to specify an 'except FooException:' in some
user of that module; this allows exceptions from that particular
module to be handled differently, if necessary. (And so on for a
hierarchy of modules in a package, if that's warranted.)
 
C

Colin J. Williams

Ben said:
Howdy all,

Okay, so Guido doesn't like Abstract Base Classes[0], and interfaces
are the way of the future[1]. But they're not here now, and I
understand ABCs better.
This is a very interesting discussion - not all of it understandable to me.

Are interfaces really in our future?

I found the contributions of "steffen" particularly appealing.
Interfaces seem to add another level of complexity without significant
benefit.

Colin W.
I want my modules to (sometimes) define an abstract base exception
class, that all other exceptions in that module inherit from.

class FooException(Exception):
""" Base class for all FooModule exceptions """

class FooBadFilename(FooException):
""" Raised when a bad filename is used in a foo """

class FooUnknownBar(FooException, KeyError):
""" Raised when an unknown bar is used with a foo """

However, there should never be an exception raised of class
FooException, and in fact I want that to cause an appropriate error to
be raised from the module.

Normally, I'd pick some key part of the functionality of the class,
and cause that to raise NotImplementedError. It's then the
responsibility of subclasses to override that.

However, in the case of exceptions, I don't want to override *any*
functionality; everything should be provided by the base classes. It'd
be messy to have to override something in every subclass just to
ensure the abstraction of the module base exception.

I've tried doing this in the __init__():

class FooException(Exception):
""" Base class for all FooModule exceptions """
def __init__(self):
raise NotImplementedError, \
"%s is an abstract class for exceptions" % self.__class__

When I use this, I discovered to my horror that the subclasses were
calling FooException.__init__ -- which I though wasn't supposed to
happen in Python!

It's also rather semantically weird, to my eye.

Can I do something tricky with checking base classes in the
FooException.__init__() ?


[0] Although he's apparently been quoted earlier as saying he did.
He's changed his mind[1] since then.

[1] <URL:http://www.artima.com/weblogs/viewpost.jsp?thread=92662>
 
B

Ben Finney

Ben Finney said:
I want my modules to (sometimes) define an abstract base exception
class, that all other exceptions in that module inherit from.

Not a whole lot of feedback on this, so here's the implementation I
decided upon.

class FooException(Exception):
""" Base class for all exceptions in this module """
def __init__(self):
if self.__class__ is EnumException:
raise NotImplementedError, \
"%s is an abstract class for subclassing" % self.__class__

class FooBarTypeError(TypeError, FooException):
""" Raised when the foo gets a bad bar """

class FooDontDoThatError(AssertionError, FooException):
""" Raised when the foo is asked to do the wrong thing """


This allows the exceptions for the module to behave similarly to their
leftmost base exception; but because they all inherit from the
abstract base class exception for the module, it also allows for this
idiom:

import foo

try:
foo.do_stuff(bar)
except FooException, e:
special_error_handler(e)


Any more comment on this technique? Any other significant use cases
for abstract base classes?
 
B

Ben Finney

Ben Finney said:
I want my modules to (sometimes) define an abstract base exception
class, that all other exceptions in that module inherit from.

[re-posting with the implementation properly foo-ified]

Not a whole lot of feedback on this, so here's the implementation I
decided upon.

class FooException(Exception):
""" Base class for all exceptions in this module """
def __init__(self):
if self.__class__ is FooException:
raise NotImplementedError, \
"%s is an abstract class for subclassing" % self.__class__

class FooBarTypeError(TypeError, FooException):
""" Raised when the foo gets a bad bar """

class FooDontDoThatError(AssertionError, FooException):
""" Raised when the foo is asked to do the wrong thing """


This allows the exceptions for the module to behave similarly to their
leftmost base exception; but because they all inherit from the
abstract base class exception for the module, it also allows for this
idiom:

import foo

try:
foo.do_stuff(bar)
except FooException, e:
special_error_handler(e)


Any more comment on this technique? Any other significant use cases
for abstract base classes?
 
S

Steven D'Aprano

Ben said:
Ben Finney said:
I want my modules to (sometimes) define an abstract base exception
class, that all other exceptions in that module inherit from.


[re-posting with the implementation properly foo-ified]

Isn't the proper Python idiom to use Monty Python
concepts, e.g. spam, vikings, parrots, after dinner
mints (wafer thin or otherwise), gumby, etc.?

As well as being Pythonic, it annoys the Lisp, Perl and
C developers even more than ... sarcasm.

*wink*
Not a whole lot of feedback on this, so here's the implementation I
decided upon.

[snip]

Seems good to me.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top