[Python-Dev] PEP 207 -- Rich Comparisons
Guido van Rossum
guido@python.org
Fri, 15 Dec 2000 14:51:04 -0500
> Here are my comments on PEP 207. (I've also gone back and read most
> of the 1998 discussion. What a tedious, in terms of time, but
> enlightening, in terms of content, discussion that was.)
>
> | - New function:
> |
> | PyObject *PyObject_RichCompare(PyObject *, PyObject *, enum cmp_op)
> |
> | This performs the requested rich comparison, returning a Python
> | object or raising an exception. The 3rd argument must be one of
> | LT, LE, EQ, NE, GT or GE.
>
> I'd much prefer '<', '<=', '=', etc. to LT, LE, EQ, etc.
This is only at the C level. Having to do a string compare is too
slow. Since some of these are multi-character symbols, a character
constant doesn't suffice (multi-character character constants are not
portable).
> | Classes
> |
> | - Classes can define new special methods __lt__, __le__, __gt__,
> | __ge__, __eq__, __ne__ to override the corresponding operators.
> | (You gotta love the Fortran heritage.) If a class overrides
> | __cmp__ as well, it is only used by PyObject_Compare().
>
> Likewise, I'd prefer __less__, __lessequal__, __equal__, etc. to
> __lt__, __le__, __eq__, etc. I'm not keen on the FORTRAN derived
> symbolism. I also find it contrary to Python's heritage of being
> clear and concise. I don't mind typing __lessequal__ (or
> __less_equal__) once per class for the additional clarity.
I don't care about Fortran, but you just showed why I think the short
operator names are better: there's less guessing or disagreement about
how they are to be spelled. E.g. should it be __lessthan__ or
__less_than__ or __less__?
> | - Should we even bother upgrading the existing types?
>
> Isn't this question partly related to the coercion issue and which
> type of comparison takes precedence? And if so, then I would think
> the answer would be 'yes'.
It wouldn't make much of a difference -- comparisons between different
types numbers would get the same outcome either way.
> Or better still see below my suggestion of
> adding poor and rich comparison operators along with matrix-type
> operators.
>
>
> - If so, how should comparisons on container types be defined?
> Suppose we have a list whose items define rich comparisons. How
> should the itemwise comparisons be done? For example:
>
> def __lt__(a, b): # a<b for lists
> for i in range(min(len(a), len(b))):
> ai, bi = a[i], b[i]
> if ai < bi: return 1
> if ai == bi: continue
> if ai > bi: return 0
> raise TypeError, "incomparable item types"
> return len(a) < len(b)
>
> This uses the same sequence of comparisons as cmp(), so it may
> as well use cmp() instead:
>
> def __lt__(a, b): # a<b for lists
> for i in range(min(len(a), len(b))):
> c = cmp(a[i], b[i])
> if c < 0: return 1
> if c == 0: continue
> if c > 0: return 0
> assert 0 # unreachable
> return len(a) < len(b)
>
> And now there's not really a reason to change lists to rich
> comparisons.
>
> I don't understand this example. If a[i] and b[i] define rich
> comparisons, then 'a[i] < b[i]' is likely to return a non-boolean
> value. Yet the 'if' statement expects a boolean value. I don't see
> how the above example will work.
Sorry. I was thinking of list items that contain objects that respond
to the new overloading protocol, but still return Boolean outcomes.
My conclusion is that __cmp__ is just as well.
> This example also makes me think that the proposals for new operators
> (ie. PEP 211 and 225) are a good idea. The discussion of rich
> comparisons in 1998 also lends some support to this. I can see many
> uses for two types of comparison operators (as well as the proposed
> matrix-type operators), one set for poor or boolean comparisons and
> one for rich or non-boolean comparisons. For example, numeric arrays
> can define both. Rich comparison operators would return an array of
> boolean values, while poor comparison operators return a boolean value
> by performing an implied 'and.reduce' operation. These operators
> provide clarity and conciseness, without much change to current Python
> behavior.
Maybe. That can still be decided later. Right now, adding operators
is not on the table for 2.1 (if only because there are two conflicting
PEPs); adding rich comparisons *is* on the table because it doesn't
change the parser (and because the rich comparisons idea was already
pretty much worked out two years ago).
--Guido van Rossum (home page: http://www.python.org/~guido/)