Rich Comparisons Gotcha

Steven D'Aprano steven at
Thu Dec 11 03:10:12 EST 2008

On Wed, 10 Dec 2008 17:58:49 -0500, Luis Zarrabeitia wrote:

> On Sunday 07 December 2008 09:21:18 pm Robert Kern wrote:
>> The deficiency is in the feature of rich comparisons, not numpy's
>> implementation of it. __eq__() is allowed to return non-booleans;
>> however, there are some parts of Python's implementation like
>> list.__contains__() that still expect the return value of __eq__() to
>> be meaningfully cast to a boolean.
> list.__contains__, tuple.__contains__, the 'if' keyword...
> How do can you suggest to fix the list.__contains__ implementation?

I suggest you don't, because I don't think it's broken. I think it's 
working as designed. It doesn't succeed with arbitrary data types which 
may be broken, buggy or incompatible with __contain__'s design, but 
that's okay, it's not supposed to.

> Should I wrap all my "if"s with this?:
> if isinstance(a, numpy.array) or isisntance(b,numpy.array):
>     res = compare_numpy(a,b)
> elif isinstance(a,some_otherclass) or isinstance(b,someotherclass):
>     res = compare_someotherclass(a,b)
> ...
> else:
>     res = (a == b)
> if res:
>    # do whatever

No, inlining that code everywhere you have an if would be stupid. What 
you should do is write a single function equals(x, y) that does precisely 
what you want it to do, in whatever way you want, and then call it:

if equals(a, b):

Or, put your data inside a wrapper. If you read back over my earlier 
posts in this thread, I suggested a lightweight wrapper class you could 
use. You could make it even more useful by using delegation to make the 
wrapped class behave *exactly* like the original, except for __eq__.

You don't even need to wrap every single item:

def wrap_or_not(obj):
    if obj in list_of_bad_types_i_know_about:
        return EqualityWrapper(obj)
    return obj

data = [1, 2, 3, BadData, 4]
data = map(wrap_or_not, data)

It isn't really that hard to deal with these things, once you give up the 
illusion that your code should automatically work with arbitrarily wacky 
data types that you don't control.


More information about the Python-list mailing list