从 python 列表中删除一个项目,如何比较项目(例如 numpy 数组)?

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

我对python(2.7)list.remove函数有点疑惑。在 documentation of remove 它说:"Remove the first item from the list whose value is x. It is an error if there is no such item."

所以,我猜这里 value 意味着比较是基于 equality(即 ==)而不是 身份(即is)。但是,有人可以向我解释以下行为。显然,这两种比较都被使用了,但是以一种相当奇怪的方式:

import numpy as np

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

这当然会打印:

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

到目前为止一切顺利。但奇怪的是,下面的代码确实执行了:

mylist.remove(x)
print mylist

给予

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

我预计它会抛出错误,因为 numpy 数组 return 不是布尔语句而是布尔数组。 例如,x == x returns array([ True, True, True], dtype=bool)。 然而,我们的删除很高兴地执行了。但是,再次调用相同的语句会产生预测的行为:

mylist.remove(x)

抛出一个

---------------------------------------------------------------------------
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()

这是怎么回事?

查看源代码,list.remove使用PyObject_RichCompareBool函数比较对象。此函数开头包含以下内容:

/* 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;
}

所以它首先比较对象标识。仅当对象不同时,它才会继续使用 == 运算符。

在您的示例中,如果 x 是列表中的第一个对象,它将与删除的值是同一个对象,因此被上述函数视为相等并被删除。如果其他对象是第一个对象,它将与 x== 运算符进行比较,这将 return 一个 numpy 数组并导致错误,因为它无法转换为布尔值。

in 运算符的工作方式相同,因此 x in [x,1] returns Truex in [1,x] 会引发错误。

第二次出现错误是因为测试 42x 的身份失败并且 Python 回退到使用等式比较 x 与整数 42 (==).

mylist.remove(x) 摆脱了列表中第一次出现的 x,没有任何问题,因为 x is x returns True。问题是,当 first 的第一个元素是 42 时,x is 42 returns False 所以 Python 会尝试 x == 42

此相等性测试 returns 数组 array([False, False, False])。与原生 Python 对象不同,NumPy 数组的真值不明确,会引发错误。