Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removal of an item from a python list, how are items compared (e.g. numpy arrays)?

I am a bit puzzled by the python (2.7) list.remove function. In the documentation of remove it says: "Remove the first item from the list whose value is x. It is an error if there is no such item."

So, I guess here value means that comparison is based on equality (i.e. ==) and not identity (i.e. is). However, can someone explain to me the following behaviour. Apparently, both comparisons are used, but in a rather strange way:

import numpy as np

x = np.array([1,2,3])
mylist = [x, 42, 'test', x] # list containing the numpy array twice
print mylist

This will, of course, print:

[array([1, 2, 3]), 42, 'test', array([1, 2, 3])]

So far so good. But strangely the following code does execute:

mylist.remove(x)
print mylist

giving

[42, 'test', array([1, 2, 3])]

I would expect it to throw an error because numpy arrays do not return a boolean statement but a boolean array. For instance, x == x returns array([ True, True, True], dtype=bool). Yet, our removal happily executes. However, calling the same statement once more yields the predicted behaviour:

mylist.remove(x)

throws a

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-835a19b5f6a9> in <module>()
----> 1 mylist.remove(x)

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

What is going on?

like image 735
SmCaterpillar Avatar asked Feb 17 '15 13:02

SmCaterpillar


1 Answers

Looking at the source code, list.remove uses the PyObject_RichCompareBool function to compare objects. This function contains the following at the beginning:

/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if (v == w) {
    if (op == Py_EQ)
        return 1;
    else if (op == Py_NE)
        return 0;
}

So it compares object identity first. Only if the objects are different, it proceeds to use the == operator.

In your example, if x is the first object in the list, it will be the same object as the removed value and therefore be regarded as equal by the above function and removed. If anything else is the first object, it will be compared to x with the == operator, which will return a numpy array and cause an error as it can't be converted to a boolean value.

The in operator works in the same way, so x in [x,1] returns True while x in [1,x] raises an error.

like image 158
interjay Avatar answered Oct 15 '22 07:10

interjay