Removing an element from a python list, how do elements (e.g. numpy arrays) compare?

I am a bit puzzled by the python (2.7) list.remove . The deletion documentation says: "Delete the first element from the list whose value is x. This is an error if there is no such element."

So, I think that the value value means that the comparison is based on equality (i.e. == ), not identity (i.e. is ). However, can someone explain the following behavior to me. Both comparisons seem to be used, but rather oddly:

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

This, of course, will print:

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

So far so good. But the following code looks strange:

 mylist.remove(x) print mylist 

gives

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

I would expect it to throw an error, because numpy arrays do not return a boolean operator, but a boolean array. For example, x == x returns array([ True, True, True], dtype=bool) . However, our removal is successful. However, a repetition of the same statement leads to predicted behavior:

 mylist.remove(x) 

throws out

 --------------------------------------------------------------------------- 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's happening?

+6
source share
2 answers

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

 /* 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, first, the identification of the object is compared. Only if the objects are different, it continues to use the == operator.

In your example, if x is the first object in the list, it will be the same object as the deleted value, and therefore will be considered equal to the above function and deleted. If something else is the first object, it will be compared with x with the == operator, which will return a numpy array and cause an error, since it cannot be converted to a boolean value.

The in operator works the same, so x in [x,1] returns True , and x in [1,x] causes an error.

+4
source

The error occurs a second time because testing 42 for identification with x fails, and Python returns to comparing x with the integer 42 using equality ( == ).

mylist.remove(x) gets rid of the first appearance of x in the list without any hiccups because x is x returns True . The problem is that when the first element of the first is 42, x is 42 returns False , so Python tries x == 42 instead.

This equality test returns an array([False, False, False]) . Unlike native Python objects, NumPy arrays have an ambiguous truth value and errors occur.

+1
source

Source: https://habr.com/ru/post/982596/


All Articles