Abstract Base Classes

Discussion in 'Python' started by Ben Finney, Nov 11, 2005.

  1. Ben Finney

    Ben Finney Guest

    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>

    --
    \ "The shortest distance between two points is under |
    `\ construction." -- Noelie Alito |
    _o__) |
    Ben Finney
     
    Ben Finney, Nov 11, 2005
    #1
    1. Advertising

  2. Ben Finney

    Mike Meyer Guest

    Ben Finney <> writes:
    > 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
    --
    Mike Meyer <> http://www.mired.org/home/mwm/
    Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
     
    Mike Meyer, Nov 11, 2005
    #2
    1. Advertising

  3. Ben Finney

    Ben Finney Guest

    Mike Meyer <> wrote:
    > 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.)

    --
    \ "A cynic is a man who knows the price of everything and the |
    `\ value of nothing." -- Oscar Wilde |
    _o__) |
    Ben Finney
     
    Ben Finney, Nov 11, 2005
    #3
  4. Ben Finney wrote:
    > 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>
    >
     
    Colin J. Williams, Nov 11, 2005
    #4
  5. Ben Finney

    Ben Finney Guest

    Ben Finney <> wrote:
    > 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?

    --
    \ "For man, as for flower and beast and bird, the supreme triumph |
    `\ is to be most vividly, most perfectly alive" -- D.H. Lawrence. |
    _o__) |
    Ben Finney
     
    Ben Finney, Nov 14, 2005
    #5
  6. Ben Finney

    Ben Finney Guest

    Ben Finney <> wrote:
    > 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?

    --
    \ "For man, as for flower and beast and bird, the supreme triumph |
    `\ is to be most vividly, most perfectly alive" -- D.H. Lawrence. |
    _o__) |
    Ben Finney
     
    Ben Finney, Nov 14, 2005
    #6
  7. Ben Finney wrote:
    > Ben Finney <> wrote:
    >
    >>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.


    --
    Steven.
     
    Steven D'Aprano, Nov 14, 2005
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. DaKoadMunky
    Replies:
    4
    Views:
    557
    Lee Weiner
    Apr 20, 2004
  2. John Gagon
    Replies:
    1
    Views:
    373
    LordAlfredHenry
    May 17, 2006
  3. pasa_1
    Replies:
    1
    Views:
    328
    mlimber
    Nov 17, 2006
  4. pasa_1
    Replies:
    0
    Views:
    302
    pasa_1
    Nov 17, 2006
  5. Bart Simpson
    Replies:
    4
    Views:
    312
    James Kanze
    Jun 3, 2007
Loading...

Share This Page