Rich Comparisons Gotcha

Robert Kern robert.kern at gmail.com
Sun Dec 7 21:21:18 EST 2008


James Stroud wrote:
> Steven D'Aprano wrote:
>> On Sun, 07 Dec 2008 13:57:54 -0800, James Stroud wrote:
>>
>>> Rasmus Fogh wrote:
> 
>>>>>>> ll1 = [y,1]
>>>>>>> y in ll1
>>>> True
>>>>>>> ll2 = [1,y]
>>>>>>> y in ll2
>>>> Traceback (most recent call last):
>>>>   File "<stdin>", line 1, in <module>
>>>> ValueError: The truth value of an array with more than one element is
>>>> ambiguous. Use a.any() or a.all()
>>> I think you could be safe calling this a bug with numpy. 
>>
>> Only in the sense that there are special cases where the array 
>> elements are all true, or all false, and numpy *could* safely return a 
>> bool. But special cases are not special enough to break the rules. 
>> Better for the numpy caller to write this:
>>
>> a.all() # or any()
>>
>> instead of:
>>
>> try:
>>     bool(a)
>> except ValueError:
>>     a.all()
>>
>> as they would need to do if numpy sometimes returned a bool and 
>> sometimes raised an exception.
> 
> I'm missing how a.all() solves the problem Rasmus describes, namely that 
> the order of a python *list* affects the results of containment tests by 
> numpy.array. E.g. "y in ll1" and "y in ll2" evaluate to different 
> results in his example. It still seems like a bug in numpy to me, even 
> if too much other stuff is broken if you fix it (in which case it 
> apparently becomes an "issue").

It's an issue, if anything, not a bug. There is no consistent implementation of 
bool(some_array) that works in all cases. numpy's predecessor Numeric used to 
implement this as returning True if at least one element was non-zero. This 
works well for bool(x!=y) (which is equivalent to (x!=y).any()) but does not 
work well for bool(x==y) (which should be (x==y).all()), but many people got 
confused and thought that bool(x==y) worked. When we made numpy, we decided to 
explicitly not allow bool(some_array) so that people will not write buggy code 
like this again.

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.

-- 
Robert Kern

"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 mailing list