Rich Comparisons Gotcha
robert.kern at gmail.com
Sun Dec 7 00:57:56 CET 2008
Terry Reedy wrote:
> Rasmus Fogh wrote:
>> Dear All,
>> For the first time I have come across a Python feature that seems
>> completely wrong. After the introduction of rich comparisons, equality
>> comparison does not have to return a truth value, and may indeed return
>> nothing at all and throw an error instead. As a result, code like
>> if foo == bar:
>> foo in alist
>> cannot be relied on to work.
>> This is clearly no accident. According to the documentation all
>> operators are allowed to return non-booleans, or to throw errors.
>> There is
>> explicitly no guarantee that x == x is True.
> You have touched on a real and known issue that accompanies dynamic
> typing and the design of Python. *Every* Python function can return any
> Python object and may raise any exception either actively, by design, or
> passively, by not catching exceptions raised in the functions *it* calls.
>> Personally I would like to get these !@#$%&* misfeatures removed,
> What you are calling a misfeature is an absence, not a presence that can
> be removed.
That's not quite true. Rich comparisons explicitly allow non-boolean return
values. Breaking up __cmp__ into multiple __special__ methods was not the sole
purpose of rich comparisons. One of the prime examples at the time was numpy
(well, Numeric at the time). We wanted to use == to be able to return an array
with boolean values where the two operand arrays were equal. E.g.
In : from numpy import *
In : array([1, 2, 3]) == array([4, 2, 3])
Out: array([False, True, True], dtype=bool)
SQLAlchemy uses these operators to build up objects that will be turned into SQL
>>> print users.c.id==addresses.c.user_id
users.id = addresses.user_id
Basically, the idea was to turn these operators into full-fledged operators like
+-/*. Returning a non-boolean violates neither the letter, nor the spirit of the
Unfortunately, if you do overload __eq__ to build up expressions or whatnot, the
other places where users of __eq__ are implicitly expecting a boolean break.
While I was (and am) a supporter of rich comparisons, I feel Rasmus's pain from
time to time. It would be nice to have an alternate method to express the
boolean "yes, this thing is equal in value to that other thing". Unfortunately,
I haven't figured out a good way to fit it in now without sacrificing rich
>> and constrain the __eq__ function to always return a truth value.
> It is impossible to do that with certainty by any mechanical
> creation-time checking. So the implementation of operator.eq would have
> to check the return value of the ob.__eq__ function it calls *every
> time*. That would slow down the speed of the 99.xx% of cases where the
> check is not needed and would still not prevent exceptions. And if the
> return value was bad, all operator.eq could do is raise and exception
Sure, but then it would be a bug to return a non-boolean from __eq__ and
friends. It is not a bug today. I think that's what Rasmus is proposing.
"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
More information about the Python-list