Rich Comparisons Gotcha

Rasmus Fogh rhf22 at mole.bio.cam.ac.uk
Sun Dec 7 08:03:43 EST 2008


Jamed Stroud 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:
>> or
>>   foo in alist
>> cannot be relied on to work.

>> This is clearly no accident. According to the documentation all
>> comparison operators are allowed to return non-booleans, or to throw
>> errors. There is
>> explicitly no guarantee that x == x is True.

> I'm not a computer scientist, so my language and perspective on the
> topic may be a bit naive, but I'll try to demonstrate my caveman
> understanding example.

> First, here is why the ability to throw an error is a feature:

> class Apple(object):
>    def __init__(self, appleness):
>      self.appleness = appleness
>    def __cmp__(self, other):
>      assert isinstance(other, Apple), 'must compare apples to apples'
>      return cmp(self.appleness, other.appleness)

> class Orange(object): pass

> Apple(42) == Orange()

True, but that does not hold for __eq__, only for __cmp__, and
for__gt__, __le__, etc.
Consider:

Class Apple(object):
  def __init__(self, appleness):
    self.appleness = appleness
  def __gt__(self, other):
     assert isinstance(other, Apple), 'must compare apples to apples'
     return (self.appleness > other.appleness)
  def __eq__(self, other):
    if  isinstance(other, Apple):
      return (self.appleness == other.appleness)
    else:
      return False

> Second, consider that any value in python also evaluates to a truth
> value in boolean context.
>
> Third, every function returns something. A function's returning nothing
> is not a possibility in the python language. None is something but
> evaluates to False in boolean context.

Indeed. The requirement would be not that return_value was a boolean, but
that bool(return_value) was defined and gave the correct result. I
understand that in some old Numeric/numpy version the numpy array __eq__
function returned a non-empty array, so that
bool(numarray1 == numarray2)
was true for any pair of arguments, which is one way of breaking '=='.
In current numpy, even
bool(numarray1 == 1)
throws an error, which is another way of breaking '=='.

>> But surely you can define an equal/unequal classification for all
>> types of object, if you want to?

> This reminds me of complex numbers: would 4 + 4i be equal to sqrt(32)?
> Even in the realm of pure mathematics, the generality of objects (i.e.
> numbers) can not be assumed.

It sounds like that problem is simpler in computing. sqrt(32) evaluates to
5.6568542494923806 on my computer. A complex number c with non-zero
imaginary part would be unequal to sqrt(32) even if it so happened that
c*c==32.

Yours,

Rasmus

---------------------------------------------------------------------------
Dr. Rasmus H. Fogh                  Email: r.h.fogh at bioc.cam.ac.uk
Dept. of Biochemistry, University of Cambridge,
80 Tennis Court Road, Cambridge CB2 1GA, UK.     FAX (01223)766002




More information about the Python-list mailing list