Interfaces versus Abstract Base Classes in Python
In his Python 3000 keynote, Guido talked about having marker interfaces to make more explicit notions like "list-like" and "file-like". As I understood it, the idea is to be able to test that an object is "list-like" or "file-like" explicitly rather than arbitrarily pick some attribute on the object to test for as the diagnostic.
What confused me at the time was that Guido was calling this feature "Abstract Base Classes".
To me, this conflates inheritance with polymorphism. Aren't abstract base classes fundamentally about inheritance of (partial) implementation? But surely this isn't what Guido is talking about—he's purely talking about the interchangeability of objects (i.e. polymorphism).
So isn't the term "abstract base class" inappropriate and potentially misleading?
Comments (9)
Jim on March 4, 2007:
The two tend to be confused because ABC is how you do interfaces in C++.
Bill Mill on March 4, 2007:
+1 Agree.
Also, that feature sounds like an excellent idea.
Bill Mill on March 4, 2007:
@ekzept:
I felt that way about decorators, but I don't feel that way about this feature. It leads the way to a more rigorous type system; I don't think it's additional moss on the language, but instead (at least has the potential to be) a substantial improvement.
Basically every serious project has an inplementation of this feature - why not solidify it into the language now that it's proven its utility?
Doug Napoleone on March 4, 2007:
I talked with a number of python-dev people and two Python 3000 sprinters about this exact question. The truth is Guido is not sure which direction to take, interfaces or abstract base classes. Abstract base classes are in some sence simpler to implement and understand (from a python C/API standpoint) and might provide 99% of what is needed by 90% of the people (far surpassing the 80/20 rule). But that might not be 'good enough' all things considered. It is one of those ** things (still being discussed what the implementation will even look like).
Pete on March 5, 2007:
So think of it as a *pure* ABC. This is a Python class like:
class foo_like:
def meth1(..)
"""does blah"""
raise NotImplementError
def meth2(..)
"""Subclassers should bar"""
raise NotImplementError
Inheriting from such a thing is a promise to *implement* all those methods in a reasonable way.
This provides a convenient way to assert isinstance(x, foo_like) at the top of a foo-using block and then blithely carry on, knowing that you've got something like a foo.
You can of course, do something more interesting than just assert, but that's the basic idea.
Jeff Shell on March 5, 2007:
Abstract Base Classes are easier to provide, I'm sure. I'm interested in seeing how they will work. Will the contain any implementation detail at all? Will they affect method resolution order? I fear they might complicate multiple inheritance hierarchies and a careless placement of the ABC by any class in the inheritance tree could ruin implementation expectations. If they're JUST a marker, I would hope there's a way to include them dynamically - again without affecting method resolution order of actual implementation.
My experience has been that in large and long running systems one has many more objects (instances) than classes, and that behavior (polymorphism) is far more important than parental lineage. If it has a bill like a duck and all I need is the bill, should I care that it's a platypus? If it quacks like a duck and all I want to do is make it quack, should I care that it's a hunter's duck call?
conformance to a specification is more important than how one grew to having that conformance. Consider large systems where there may be a lot of proxies / wrappers. An object may wrap a stream. The outer (wrapping) object may not provide the 'write' method, but will pass control of 'write' to the inner (wrapped) object. The outer object should still be considered a writable stream. This relationship may not be known until run time. If the outer object agrees to take on the wrapped objects responsibilities, it should have a way of declaring as such.
`isinstance()` fails in those cases. We found this out on a data transformation system we've developed. Objects get wrapped and wrapped and wrapped, but we still need to know "is this a DataSet I see before me, or a Data?"
Using Interfaces, one could have ``if IDataSet.providedBy(obj)``. Or ``conform(obj, IDataSet)``.
Future growth gets especially limited if you restrict declaration of common protocol support to the inheritance hierarchy which is usually established at compile time.
I hope that if abstract base classes are the chosen way, then something along the lines of PEP 246 (object adaptation, which was rejected) might get picked up as well.
The Erratic Programmer on March 7, 2007:
What about?
(replace /^.*/ with / /)
def implements(obj,cls):
.original = dir(obj.__class__)
.target = dir(cls)
..for x in target:
...if x not in original:
....return False
..else:
...return True
shameless plug for http://theerratic.blogspot.com/2007/03/python-abstract-classes-vs-interfaces.html
Like i said, this is an IDE thing not a langue thing ne?
chromatic on April 3, 2007:
ABCs and interfaces (at least in the Java style) have severe problems. Smalltalk traits or Perl 6 roles solve those problems. See <a href="http://www.oreillynet.com/onlamp/blog/2006/08/roles_composable_units_of_obje.html">Roles: Composable Units of Object Behavior</a> for a fuller discussion.
Last Modified: March 4, 2007
Author: James Tauber
ekzept on March 4, 2007:
isn't it a tad bit disturbing to anyone that, despite the excellent guidance va Rossum is providing, Python is growing rather like PERL and PHP, accumulating moss as it rolls along? what happened to the idea of a nice, neat core definitional language in/from which all else can described/defined? or was that never a goal of Python? (sorry, don't know.)
if it wasn't, perhaps that explains the marginal and lingering LISP/Scheme-envy in the peanut gallery?