views:

798

answers:

12

So I'm starting a project using Python after spending a significant amount of time in static land. I've seen some projects that make "interfaces" which are really just classes without any implementations. Before, I'd scoff at the idea and ignore that section of those projects. But now, I'm beginning to warm up to the idea.

Just so we're clear, an interface in Python would look something like this:

class ISomething(object):
    def some_method():
        pass
    def some_other_method(some_argument):
        pass

Notice that you aren't passing self to any of the methods, thus requiring that the method be overriden to be called. I see this as a nice form of documentation and completeness testing.

So what is everyone here's opinion on the idea? Have I been brainwashed by all the C# programming I've done, or is this a good idea?

+1  A: 

My personal opinion is positive regarding these interfaces in Python, though I haven't actually use Python interfaces.

I have used them quite a bit in PHP with a project because the interfaces really did make that completeness testing you mentioned quite simple.

Rishabh Mishra
+5  A: 

Seems kind of unnecessary to me - when I'm writing classes like that I usually just make the base class (your ISomething) with no methods, and mention in the actual documentation which methods subclasses are supposed to override.

David Zaslavsky
+2  A: 

I'm about to do something similar with my Python project, the only things I would add are:

  • Extra long, in-depth doc strings for each interface and all the abstract methods.
  • I would add in all the required arguments so there's a definitive list.
  • Raise an exception instead of 'pass'.
  • Prefix all methods so they are obviously part of the interface - interface Foo: def foo_method1()
too much php
Just to add -- the specific exception to raise would be NotImplementedError()
che
I like all your suggestions except for the 4th. It's unnecessarily verbose, IMO.Also, a link to the NotImplementedError docs: http://docs.python.org/library/exceptions.html#exceptions.NotImplementedError
Kamil Kisiel
+1: Raise NotImplementedError instead of pass. -1: never use extra names like foo_method. Never.
S.Lott
+10  A: 

there are some cases where interfaces can be very handy. twisted makes fairly extensive use of zope interfaces, and in a project i was working on zope interfaces worked really well. enthought's traits packaged recently added interfaces, but i don't have any experience with them.

beware overuse though -- duck typing and protocols are a fundamental aspect of python, only use interfaces if they're absolutely necessary.

Autoplectic
+4  A: 

I don't think interfaces would add anything to the code environment.

  • Method definition enforcing happens without them. If an object expected to be have like Foo and have method bar(), and it does't, it will throw an AttributeError.
  • Simply making sure an interface method gets defined doesn't guarantee its correctness; behavioral unit tests need to be in place anyway.
  • It's just as effective to write a "read this or die" page describing what methods your object needs to have to be compatible with what you're plugging it in as having elaborate docstrings in an interface class, since you're probably going to have tests for it anyway. One of those tests can be standard for all compatible objects that will check the invocation and return type of each base method.
Dimitri Tcaciuc
+7  A: 

The pythonic way is to "Ask for forgiveness rather than receive permission". Interfaces are all about receiving permission to perform some operation on an object. Python prefers this:

def quacker(duck):
    try:
        duck.quack():
    except AttributeError:
        raise ThisAintADuckException
Triptych
+3  A: 

You can create an interface in a dynamically typed language, but there's no enforcement of the interface at compile time. A statically typed language's compiler will warn you if you forget to implement (or mistype!) a method of an interface. Since you receive no such help in a dynamically typed language, your interface declaration serves only as documentation. (Which isn't necessarily bad, it's just that your interface declaration provides no runtime advantage versus writing comments.)

Neil Mix
+22  A: 

I'm not sure what the point of that is. Interfaces (of this form, anyway) are largely to work around the lack of multiple inheritance. But Python has MI, so why not just make an abstract class?

class Something(object):
    def some_method(self):
        raise NotImplementedError()
    def some_other_method(self, some_argument):
        raise NotImplementedError()
Ken
+1: I was going to suggest the same thing, but you beat me to it. This is much more Pythonic because it gives the proper error when the method isn't implemented, but doesn't require a method to be implemented if it won't be used in the context of the subclass.
Daniel
Also, when writing Java one often writes interfaces plus abstract classes. The subclass extends an abstract class, which implements the interface. The interface is redundant, but is expected due to convention. Duck typing removes the idiocy, but sometimes I find this kind of base class very useful.
Daniel
+6  A: 

In Python 2.6 and later, you can use abstract base classes instead. These are useful, because you can then test to see if something implements a given ABC by using "isinstance". As usual in Python, the concept is not as strictly enforced as it would be in a strict language, but it's handy. Moreover there are nice idiomatic ways of declaring abstract methods with decorators - see the link above for examples.

jlarcombe
+1  A: 

I personally use interfaces a lot in conjunction with the Zope Component Architecture (ZCA). The advantage is not so much to have interfaces but to be able to use them with adapters and utilities (singletons).

E.g. you could create an adapter which can take a class which implements ISomething but adapts it to the some interface ISomethingElse. Basically it's a wrapper.

The original class would be:

class MyClass(object):
  implements(ISomething)

  def do_something(self):
      return "foo"

Then imagine interface ISomethingElse has a method do_something_else(). An adapter could look like this:

class SomethingElseAdapter(object):
    implements(ISomethingElse)
    adapts(ISomething)

    def __init__(self, context):
        self.context = context

    def do_something_else():
        return self.context.do_something()+"bar"

You then would register that adapter with the component registry and you could then use it like this:

>>> obj = MyClass()
>>> print obj.do_something()
"foo"
>>> adapter = ISomethingElse(obj)
>>> print adapter.do_something_else()
"foobar"

What that gives you is the ability to extend the original class with functionality which the class does not provide directly. You can do that without changing that class (it might be in a different product/library) and you could simply exchange that adapter by a different implementation without changing the code which uses it. It's all done by registration of components in initialization time.

This of course is mainly useful for frameworks/libraries.

I think it takes some time to get used to it but I really don't want to live without it anymore. But as said before it's also true that you need to think exactly where it makes sense and where it doesn't. Of course interfaces on it's own can also already be useful as documentation of the API. It's also useful for unit tests where you can test if your class actually implements that interface. And last but not least I like starting by writing the interface and some doctests to get the idea of what I am actually about to code.

For more information you can check out my little introduction to it and there is a quite extensive description of it's API.

MrTopf
+1  A: 

Glyph Lefkowitz (of Twisted fame) just recently wrote an article on this topic. Personally I do not feel the need for interfaces, but YMMV.

zgoda
+1  A: 

Have you looked at PyProtocols? it has a nice interface implementation that you should look at.

Levi Campbell