On 10/30/07, Steven Bethard <[EMAIL PROTECTED]> wrote: > On 10/30/07, Adam Olsen <[EMAIL PROTECTED]> wrote: > > It's clear to me that the opposition to removing __cmp__ comes down to > > "make the common things easy and the rare things possible". Removing > > __cmp__ means one of the common things (total ordering) becomes hard. > > I don't really think that's it. I don't see much of a difference in > difficulty between writing:: > > class C(TotalOrderingMixin): > def __lt__(self, other): > self.foo < other.foo > def __eq__(self, other): > self.foo == other.foo > > or writing [1] :: > > class C(object): > def __cmp__(self, other): > if self.foo < other.foo: > return -1 > elif self.foo < other.foo: > return 1 > else: > return 0 > > The main motivation seems really to be efficiency for a particular > task. For some tasks, e.g. sorting, you really only need __lt__, so > going through __cmp__ will just be slower. For other tasks, e.g. > comparing objects with several components, you know you have to do > both the __lt__ and __eq__ comparisons, so it would be wasteful to > make two calls when you know you could do it in one through __cmp__. > > So it's not really about making things easier or harder, it's about > making the most efficient tool for the task available. > > Steve > > [1] Yes, of course, you could just write cmp(self.foo, other.foo), but > this is how it's been written in the rest of the thread, so I have to > assume that it's more representative of real code.
cmp and __cmp__ are doomed, due to unorderable types now raising exceptions: >>> cmp(3, 'hello') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unorderable types: int() < str() >>> 3 == 'hello' False A mixin for __cmp__ would be sufficient for scalars (where you can avoid this exception and your size is constant), but not for containers (which need to avoid inappropriate types and wish to avoid multiple passes.) I don't think __richcmp__ makes the process quite as simple as we want though: class C(RichCmpMixin): def __richcmp__(self, other, mode): if not isinstance(other, C): return NotImplemented for a, b in zip(self.data, other.data): result = richcmp(a, b, mode) # XXX how do I know when to stop if all I'm doing is a # <= comparison? cmp() is much easier! return richcmp(len(self.data), len(other.data), mode) If you standardize the meaning of the return values, rather than changing meaning based upon arguments, the whole thing works much better. A simple ordered flag indicates the extent of your comparison. Returning a false value always means equal, while returning a true value means unequal possibly with a specific ordering. class C: def __richcmp__(self, other, ordered): if not isinstance(other, C): return NotImplemented for a, b in zip(self.data, other.data): result = richcmp(a, b, ordered) if result: return result return richcmp(len(self.data), len(other.data), ordered) It also occurs to me that, if a type doesn't use symmetric comparisons, it should raise an exception rather than silently doing the wrong thing. To do that you need to know explicitly when ordering is being done (which richcmp/__richcmp__ does.) -- Adam Olsen, aka Rhamphoryncus _______________________________________________ Python-3000 mailing list Python-3000@python.org http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com