Rich Comparisons Gotcha
robert.kern at gmail.com
Mon Dec 8 03:21:18 CET 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
>>>>>>> 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:
>> except ValueError:
>> 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.
"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