Rich Comparisons Gotcha

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Thu Dec 11 04:28:02 CET 2008


On Wed, 10 Dec 2008 17:21:51 -0500, Luis Zarrabeitia wrote:

> I do numeric work... I'm finishing my MSc in applied math and I'm
> programing mostly with python. And I'd rather have a.compare_with(b), or
> a.elementwise_compare(b), or whatever name, rather than (a==b).all(). 

Unluckily for you, the Numeric/Numpy people wanted something else. They 
asked first, there's a lot more of them, and their project is very 
important to Python's continued success.



> In
> fact, I'd very much like to have an a.compare_with(b, epsilon=e).all()
> (to account for rounding errors), and with python2.5,
> all(a.compare_with(b)).
> 
> Yes, I could create an element_compare(a,b) function. 

Absolutely.


> But I still can't use a==b and have a meaningful result. 

That's right. *ANY* operation in Python can fail, given arbitrary data, 
with the possible exception of the id() function and the "is" and "is 
not" operators. You have to deal with it.


> Ok, I can (and do) ignore that,
> it's just one library, I'll keep track of the types before asking for
> equality (already an ugly thing to do in python), but the a==b behaviour
> breaks the lists (a in ll, ll.indexof(a)) even for elements not in
> numpy. ¿Should I also ignore lists?

That depends on what sort of contract your code is giving. Does it 
promise to work with any imaginable data whatsoever, no matter how badly 
broken or poorly designed or incompatible with what you're trying to do?

If so, then I suggest your contract is broken, not the behaviour of list. 
You can't make trustworthy promises to deal with arbitrary data types 
that you don't control, that can fail in arbitrary ways. Here's something 
for you to consider:

class Boobytrap:
    def __eq__(self, other):
        if other == 1:
            return True
        elif other == 2:
            while True:
                pass
        return False

>>> alist = [0, Boobytrap(), 2, 3]
>>> 1 in alist
True
>>> 3 in alist
True
>>> 5 in alist
False
>>> 2 in alist


What do you expect should happen?


 
> The concept of equality between two arrays is very well defined, as it
> is also very well defined the element-by-element comparison. There is a
> need to test for both - then the way to test for equality should be the
> equality test.

The Numpy people disagree with you. It was from their request that Python 
was changed to allow __eq__ to return arbitrary objects.




-- 
Steven



More information about the Python-list mailing list