[Python-3000] Special methods and interface-based type system

Guido van Rossum guido at python.org
Wed Nov 22 21:09:31 CET 2006


On 11/22/06, Bill Janssen <janssen at parc.com> wrote:
> Talking about the Abilities/Interfaces made me think about some of our
> "rogue" special method names.  In the Language Reference, it says, "A
> class can implement certain operations that are invoked by special
> syntax (such as arithmetic operations or subscripting and slicing) by
> defining methods with special names."  But there are all these methods
> with special names like __len__ or __unicode__ which seem to be
> provided for the benefit of built-in functions, rather than for
> support of syntax.  Presumably in an interface-based Python, these
> methods would turn into regularly-named methods on an ABC, so that
> __len__ would become
>
>   class container:
>     ...
>     def len(self):
>       raise NotImplemented
>
> Though, thinking about it some more, I don't see why *all* syntactic
> operations wouldn't just invoke the appropriate normally-named method
> on a specific ABC.  "<", for instance, would presumably invoke
> "object.lessthan" (or perhaps "comparable.lessthan").  So another
> benefit would be the ability to wean Python away from this
> mangled-name oddness, which seems to me an HCI improvement.

Hm. I'm not sure I agree (figure that :-).

There are two bits of "Python rationale" that I'd like to explain first.

First of all, I chose len(x) over x.len() for HCI reasons (def
__len__() came much later). There are two intertwined reasons
actually, both HCI:

(a) For some operations, prefix notation just reads better than
postfix -- prefix (and infix!) operations have a long tradition in
mathematics which likes notations where the visuals help the
mathematician thinking about a problem. Compare the easy with which we
rewrite a formula like x*(a+b) into x*a + x*b to the clumsiness of
doing the same thing using a raw OO notation.

(b) When I read code that says len(x) I *know* that it is asking for
the length of something. This tells me two things: the result is an
integer, and the argument is some kind of container. To the contrary,
when I read x.len(), I have to already know that x is some kind of
container implementing an interface or inheriting from a class that
has a standard len(). Witness the confusion we occasionally have when
a class that is not implementing a mapping has a get() or keys()
method, or something that isn't a file has a write() method.

Saying the same thing in another way, I see 'len' as a built-in
*operation*. I'd hate to lose that. I can't say for sure whether you
meant that or not, but 'def len(self): ...' certainly sounds like you
want to demote it to an ordinary method. I'm strongly -1 on that.

The second bit of Python rationale I promised to explain is the reason
why I chose special methods to look __special__ and not merely
special. I was anticipating lots of operations that classes might want
to override, some standard (e.g. __add__ or __getitem__), some not so
standard (e.g. pickle's __reduce__ for a long time had no support in C
code at all). I didn't want these special operations to use ordinary
method names, because then pre-existing classes, or classes written by
users without an encyclopedic memory for all the special methods,
would be liable to accidentally define operations they didn't mean to
implement, with possibly disastrous consequences. Ivan Krstić
explained this more concise in his message, which arrived after I'd
written all this up.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list