Sure, some things about Python bug me. But that's not what this is about. I wanted to react to Jacob Kaplan-Moss's gripes instead of promulgating my own. Specifically, his problem with Python's interfaces, or lack thereof.
I think I can keep this brief: interfaces are a hack that Java uses because Gosling et al thought multiple inheritance was too confusing and/or dangerous. (I believe I've read something recently where Gosling said that this was one decision he might do differently if he were re-designing Java now with the benefit of hindsight, but I can't find the source. Anyone remember seeing that?)
Python has MI. It doesn't need interfaces. I'm a little baffled that someone on the django core team would cite this as a problem with Python.
Jacob's precise objection is,
I shouldn’t need to care care about the difference between something that pretends to be a list and something that really is a list.
That's just it! You don't! But of course what Jacob really means is, "It should be easy to discover what methods a library expects to find on MY object that pretends to be a list." Which seems reasonable. And sure, good documentation is always welcome.
But when you cross the line to an Interface, at least the kind of Interface where Python itself would raise an error if I ignored the recommendation and left a method out (because I knew it wasn't necessary), that's bondage & discipline. That's not Python.
Comments
From an interview.
* specification what a class should implement in order to comply with an interface. This is really useful information to have if you have a large system with many plugin points. Of course you can still cheat, it's just information.
* a way to organize API documentation. The docstrings on the interfaces are API documentation.
* the already mentioned adapter lookup. "I have this object, I want a way to render it to HTML. Oh, I do IShowAsHTML(object)". If the object already implements IShowAsHTML, the object is returned. If not, it'll look in a registry to see whether any adapter is registered for it, by the application or an extension to this application. It'll do "that_adapter(obj)" and return an object that has the API specified by IShowAsHTML. Very powerful way to have objects that do only 1 thing well (instead of inheriting a zillion base classes), and very pluggable.
There are some drawbacks, mostly to do with increased indirection in the application (which always can make something harder to understand). It's also more typing. This is bad for smaller applications, but if you have a large framework with many plugin points, it is worthwhile.
Zope 3 makes interfaces even more useful with its registries. You can use the interface spec as a lookup mechanism. Something similar is entry points in setuptools; but with Interfaces you have objects as well as names. Thus the 'buffet' templating plug-ins might be registered and looked up with `buffetspec.ITemplatePlugin`. ITemplatePlugin is an object. That means `buffetspec.interfaces.ITemplatePlugin` could be a valid reference as well. By using objects instead of mere strings as identifiers, you start to get the same rich benefits that you get when you replace string exceptions with Exception classes/objects.
But it's not bondage and discipline, these Zope interfaces. There are tools that can be used to verify an implementation: add two lines to a unit or doc test and you can check to make sure you're meeting the ITemplatePlugin spec. If it changes in the future, you can be warned by running your test suite. But it won't stop your code from compiling and executing.
Many large projects that start to develop APIs and specifications for extending the system can benefit from a formal tool for declaring those specifications and/or testing against them; and it's nice to separate out the specification from implementation, but to still be able to use that spec in code. zope.interface provides a solution that I believe is still Pythonic.
That's what I think JKM's interface gripe means. Does cgi.FieldStorage require .readline(size)?
http://mail.python.org/pipermail/web-sig/2006-September/002268.html
Interfaces are just one of those ideas that seems ok on the surface but is really worse than the problem it's supposed to be solving.
Anyway, you've prodded me into smacking some neurons together. I don't think that the interface names are that important -- they could be anonymous and I wouldn't care. I'll try to post some Python code below as an example:
class FieldStorage:
@expects(fp=project.intf.Whatevah)
def __init__(self, fp=None, ...):
....
And @expects() uses introspection to check if the fp= argument if gets supports that interface.
I guess this is where Faassen chimes in and points out I'm reinventing the wheel Zope has already made available; I haven't even looked at zope.interface. Will do.
I'd prefer to specify what I, as user of an instance, need; ZopeInterface says what interface provides and let's me check if the instance I got implements that interface.
Some points the Zope guys have dealed with: an "interface" is more than signatures -- it's also invariants (I'll go ahead and call it a contract). And I don't know how to say that.
I guess it's time for me to write up @expects(). Maybe I'll "activate" it only when 'DEBUG' in os.environ (C tradition lives on!).