Rich Comparisons Gotcha

Steven D'Aprano steven at
Mon Dec 8 04:39:09 CET 2008

On Sun, 07 Dec 2008 16:23:59 +0000, Rasmus Fogh wrote:

> Just to keep you from shooting at straw men:
> I would have liked it to be part of the design contract (a convention,
> if you like) that
> 1) bool(x == y) should return a boolean and never throw an error 

Can't be done without making bool a "magic function". If x==y raises an 
exception, bool() won't even be called. The only way around that would be 
for the Python compiler to recognise bool(x=y) and perform special magic.

What if you did this?

trueorfalse = bool  # I don't like George Boole
trueoffalse( [x][0].__class__.__getattr__('__dict__')['__eq__'](y) )

Should that have special magic performed too? Just how much work must the 
compiler put in to special-casing bool?

> 2) x == x return True

Which goes against the IEEE 754 floating-point standard.

Python used to optimize x==x and always return True. This was removed 
because it caused problems.

> I do *not* say that bool(x) should never throw an error. I do *not* say
> that Python should guess a return value if an __eq__ function throws an
> error,

But to get what you want, the above is implied.

I suppose, just barely, that you could avoid making bool() magic and just 
make if magic. When the compiler sees "if expr": it could swallow all 
exceptions inside expr and force it to evaluate to True or False. (How? 
By guessing? Randomly?) This would cause many problems, but it could be 
done, and much easier than ensuring that bool(x) always succeeds.

> only that it should have been considered a bug, or at least bad
> form, for __eq__ functions to do so.

It's certainly *unusual* for comparisons to return non-bools, but it's 
not bad form.

> What might be a sensible behaviour (unlike your proposed wrapper) 

What do you dislike about my wrapper class? Perhaps it is fixable.

> would be the following:
> def eq(x, y):
>   if x is y:
>     return True

I've already mentioned NaNs. Sentinel values also sometimes need to 
compare not equal with themselves. Forcing them to compare equal will 
cause breakage.

>   else:
>     try:
>       return (x == y)
>     except Exception:
>       return False

Why False? Why not True? If an error occurs inside __eq__, how do you 
know that the correct result was False?

class Broken(object):
    def __eq__(self, other):
        return Treu  # oops, raises NameError


More information about the Python-list mailing list