Pythonic Abstract Base Class / Interface

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tom Evans

    Pythonic Abstract Base Class / Interface

    My basic question:
    If I have a specific interface which I know is going to be implemented
    by a number of classes, but there is no implementation commonality
    between them, what is the preferred form for this in Python?

    In a staticly typed language like c++ or java, I'd describe the interface
    first, then create the classes eithered derived from that ABC or
    implementing that interface (same thing really). This was the first
    thing I thought to do in python, but then rapidly realised I didn't
    actually need to write anything in the base class - as long as code using
    one of the implemented classes just tries to do things with it it
    would just work. In fact, I didn't even need to make a base class at
    all if the calling code never checks for type (as seems normal).

    So, as I see it I could:
    a) create a base class with stubs for all the interface and derive from that.
    b) create an empty base class and derive from that.
    c) just make the concrete classes directly with no inheritance commonality.

    Is there a clear pythonic way, or does it depend a bit more on the
    design of the specific program?

    Tom
  • Michael Hudson

    #2
    Re: Pythonic Abstract Base Class / Interface

    Tom Evans <tom_evans_a@uk .co.yahoo.rever se> writes:
    [color=blue]
    > My basic question:
    > If I have a specific interface which I know is going to be implemented
    > by a number of classes, but there is no implementation commonality
    > between them, what is the preferred form for this in Python?[/color]
    [...][color=blue]
    > So, as I see it I could:
    > a) create a base class with stubs for all the interface and derive from that.
    > b) create an empty base class and derive from that.
    > c) just make the concrete classes directly with no inheritance commonality.
    >
    > Is there a clear pythonic way, or does it depend a bit more on the
    > design of the specific program?[/color]

    I'd say c) was probably the most pythonic, but it depends a bit. a)
    might have some documentation value -- for instance, you could
    document required relations between the methods in their docstrings.

    Cheers,
    mwh

    --
    In the 1950s and 60s there was a regular brain drain of young
    Australians from the cities to London, but it was because of
    money, culture and opportunity, not spiders.
    -- Al Grant, ucam.chat, from Owen Dunn's review of the year

    Comment

    • Eric Brunel

      #3
      Re: Pythonic Abstract Base Class / Interface

      Michael Hudson wrote:[color=blue]
      > Tom Evans <tom_evans_a@uk .co.yahoo.rever se> writes:
      >
      >[color=green]
      >>My basic question:
      >>If I have a specific interface which I know is going to be implemented
      >>by a number of classes, but there is no implementation commonality
      >>between them, what is the preferred form for this in Python?[/color]
      >
      > [...]
      >[color=green]
      >>So, as I see it I could:
      >>a) create a base class with stubs for all the interface and derive from that.
      >>b) create an empty base class and derive from that.
      >>c) just make the concrete classes directly with no inheritance commonality.
      >>
      >>Is there a clear pythonic way, or does it depend a bit more on the
      >>design of the specific program?[/color]
      >
      >
      > I'd say c) was probably the most pythonic, but it depends a bit. a)
      > might have some documentation value -- for instance, you could
      > document required relations between the methods in their docstrings.[/color]

      Another argument in favor of a) is that pychecker has an option to check if
      methods only raising exceptions in a super-class are actually implemented in all
      its sub-classes. So:

      class MyInterface:
      def spam(self):
      raise NotImplementedE rror
      class MyClass(MyInter face):
      ...

      has actually more than a documentation value: pychecker should at least report a
      warning if the method spam is not defined in MyClass.

      HTH
      --
      - Eric Brunel <eric dot brunel at pragmadev dot com> -
      PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com

      Comment

      • KefX

        #4
        Re: Pythonic Abstract Base Class / Interface

        >So, as I see it I could:[color=blue]
        >a) create a base class with stubs for all the interface and derive from that.
        >b) create an empty base class and derive from that.
        >c) just make the concrete classes directly with no inheritance commonality.[/color]

        It's funny, I was actually thinking about the same thing not long before this
        got posted.

        Being a newcomer of sorts to Python, I can't really comment on what's
        "Pythonic" or not as well as others can (and only Guido knows for sure), but I
        can make some guesses. Pythonic in my mind is clear, concise, but flexible.
        This is a case where you can't get all of them at the same time. The most
        concise, of course, is answer C, at the possible expense of clarity and
        flexibility. Clarity may be more important to you, and the winner for that is
        A. (Somebody else suggested using docstrings in the stubs; I second that
        opinion.) However, A is less concise.

        A and B are both flexible, because you can implement more functions in the base
        class, and poof! Derived classes gain the benefits right then and there. But of
        course you have to make sure you don't break any of them (if you're careful and
        you know what classes are derived from it, and I'm guessing you do, it
        shouldn't be a problem). I'm inclined to say that B is more flexible than A,
        because if you remove a stub function and some code somewhere relies on it
        being called (whether or not it's a no-op), then a derived class that doesn't
        define it will be broken. Of course, in practice, this isn't too likely...

        To summarize:
        C is concise and nothing else
        B is concise (not quite as much as C), somewhat clear, flexible
        A is clear, flexible (not quite as much as B), but not concise

        I'm inclined to pick A, since I'm a bit of a clarity freak, but I don't really
        feel that any one of these is more Pythonic than another on its own merits...it
        kind of depends on the situation. If subclasses are likely to be small, I would
        probably pick C or at most B and save some effort...if subclasses are likely to
        be a significant size, I'd definitely pick A.

        - Kef

        Comment

        • Alex Martelli

          #5
          Re: Pythonic Abstract Base Class / Interface

          Tom Evans wrote:
          [color=blue]
          > My basic question:
          > If I have a specific interface which I know is going to be implemented
          > by a number of classes, but there is no implementation commonality
          > between them, what is the preferred form for this in Python?[/color]
          ...[color=blue]
          > Is there a clear pythonic way, or does it depend a bit more on the
          > design of the specific program?[/color]

          The normal Python approach is currently to just rely on signature-based
          polymorphism -- use inheritance to share implementation, but if you
          have no implementation to share, there's no real reason to inherit.

          Of course, people coming from languages where inheritance reigns will
          not accept that easily and refer to such issues as:

          -- in your 'interface class' you can implement the methods as raising
          NotImplementedE rror, which will be clearer than the AttributeError
          that happens upon trying to call the method on an instance of a
          class that's meant to implement the interface but forgot the
          method in question

          -- inheritance is ALMOST always centered on sharing implementation --
          in the case of exception handling, though, inheritance trees do matter

          -- if you inherit you can typetest with isinstance rather than just
          featuretest with hasattr (to me, that's a DEFECT of inheritance:-)

          If you do have any useful features -- most often Template Method
          design patterns -- to share among (some of) your concrete classes,
          then by all means use inheritance for that. But, otherwise, I think
          that keeping documentation in comments and docstring, and using
          other language constructs (including inheritance0 for substantial
          purposes and not "just to document things", is a preferable approach.


          Alex

          Comment

          • Bruno Desthuilliers

            #6
            Re: Pythonic Abstract Base Class / Interface

            Tom Evans wrote:[color=blue]
            > My basic question:
            > If I have a specific interface which I know is going to be implemented
            > by a number of classes, but there is no implementation commonality
            > between them, what is the preferred form for this in Python?
            >
            > In a staticly typed language like c++ or java, I'd describe the interface
            > first, then create the classes eithered derived from that ABC or
            > implementing that interface (same thing really). This was the first
            > thing I thought to do in python, but then rapidly realised I didn't
            > actually need to write anything in the base class - as long as code using
            > one of the implemented classes just tries to do things with it it
            > would just work. In fact, I didn't even need to make a base class at
            > all if the calling code never checks for type (as seems normal).
            >
            > So, as I see it I could:
            > a) create a base class with stubs for all the interface and derive from that.
            > b) create an empty base class and derive from that.
            > c) just make the concrete classes directly with no inheritance commonality.
            >
            > Is there a clear pythonic way, or does it depend a bit more on the
            > design of the specific program?[/color]

            c), unless you have a compelling technical reason -> then a) with
            NotImplementedE rrors or like... I cannot see what's the b) option would
            buy you anyway.

            Work with the language, not against it.

            Bruno

            Comment

            • Fredrik Lundh

              #7
              Re: Pythonic Abstract Base Class / Interface

              Bruno Desthuilliers wrote:
              [color=blue][color=green]
              > > So, as I see it I could:
              > > a) create a base class with stubs for all the interface and derive from that.
              > > b) create an empty base class and derive from that.
              > > c) just make the concrete classes directly with no inheritance commonality.
              > >
              > > Is there a clear pythonic way, or does it depend a bit more on the
              > > design of the specific program?[/color]
              >
              > c), unless you have a compelling technical reason -> then a) with
              > NotImplementedE rrors or like... I cannot see what's the b) option would
              > buy you anyway.[/color]

              isinstance

              </F>




              Comment

              • Erik Max Francis

                #8
                Re: Pythonic Abstract Base Class / Interface

                Tom Evans wrote:
                [color=blue]
                > If I have a specific interface which I know is going to be implemented
                > by a number of classes, but there is no implementation commonality
                > between them, what is the preferred form for this in Python?[/color]
                ...[color=blue]
                > Is there a clear pythonic way, or does it depend a bit more on the
                > design of the specific program?[/color]

                I usually do something like

                class AbstractBase:
                def __init__(self):
                if self.__class__ is AbstractBase:
                raise NotImplementedE rror

                def aMethod(self):
                raise NotImplementedE rror

                def anotherMethod(s elf):
                raise NotImplementedE rror

                --
                Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
                __ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
                / \ We grow in time to trust the future for our answers.
                \__/ Ruth Benedict

                Comment

                • Dave Kuhlman

                  #9
                  Re: Pythonic Abstract Base Class / Interface

                  Erik Max Francis wrote:
                  [color=blue]
                  > Tom Evans wrote:
                  >[color=green]
                  >> If I have a specific interface which I know is going to be
                  >> implemented by a number of classes, but there is no
                  >> implementation commonality between them, what is the preferred
                  >> form for this in Python?[/color]
                  > ...[color=green]
                  >> Is there a clear pythonic way, or does it depend a bit more on
                  >> the design of the specific program?[/color]
                  >
                  > I usually do something like
                  >
                  > class AbstractBase:
                  > def __init__(self):
                  > if self.__class__ is AbstractBase:
                  > raise NotImplementedE rror
                  >[/color]
                  [snip]

                  If you expect anyone else (or yourself when you've forgotten this
                  code) to implement another derived class (to implement the
                  interface), then you will also want to add doc strings to each of
                  the methods, so that an implementer of your interface knows what
                  the requirements are for each parameter, return values, etc.
                  Implementing the (empty) base class is a good way to provide
                  documentation on your interface.

                  Dave

                  --
                  Dave Kuhlman

                  dkuhlman@rexx.c om

                  Comment

                  • Tom Evans

                    #10
                    Re: Pythonic Abstract Base Class / Interface

                    Tom Evans wrote:[color=blue]
                    > So, as I see it I could:
                    > a) create a base class with stubs for all the interface and derive from that.
                    > b) create an empty base class and derive from that.
                    > c) just make the concrete classes directly with no inheritance commonality.[/color]

                    Thanks for all the responses. It would appear that there is no
                    One True Way. What I've learnt:

                    I was originally just whipping something up, not sure what the final
                    solution was going to look like. In that case, it would appear (c)
                    was the way to go.

                    If I wanted to document exactly what the interface should be once I'm sure
                    it's the right solution, (a) with document strings and raising
                    NotImplementedE rror might be a good place to put that documentation.
                    (btw, thanks -- I didn't know about NotImplementedE rror before)

                    On the face of it, (b) appears to be the loser. But it would give me
                    isinstance if I wanted it, and might allow me to convert more easily
                    from (a) to (c) in the future.

                    thanks to all,
                    Tom

                    Comment

                    Working...