Py学习  »  Python

当元素包含numpy数组时,无法测试python列表元素的成员身份

nos • 3 年前 • 1206 次点击  

我使用 namedtuple ,其中包含numpy数组。

from collections import namedtuple
import numpy as np

AA = namedtuple('AA', 'name, x')
c = []
c.append(AA('x', np.arange(3)))
c.append(AA('x', np.arange(3)))
c.append(AA('y', np.arange(3)))
c[0] in c
c[1] in c
c[2] in c

奇怪的是 c[1] 测试失败了,而另外两个可以工作。

ValueError                                Traceback (most recent call last)
<ipython-input-70-c1daf83cd082> in <module>
----> 1 c[1] in c

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

这个错误似乎与numpy-arrray等式测试有关 c[0].x == c[1].x .但由于某种原因,第一个元素的成员资格测试总是成功的

s = []
s.append(np.arange(3))
s.append(np.arange(3))
s[0] in s
s[1] in s

再看看这个例子

class A:
    def __eq__(self, other):
        raise ValueError
        
a = [A(), A()]
a[0] in a
a[1] in a

我也不知道为什么 c[2] in c 返回 True .

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/131791
 
1206 次点击  
文章 [ 1 ]  |  最新文章 3 年前
Daniel Konstantinov
Reply   •   1 楼
Daniel Konstantinov    4 年前

简化:

def my_in(obj, container):
    for elem in container:
        if bool(my_compare_equal(obj, elem)):
            return True
    return False

def my_compare_equal(obj, elem):
    if id(obj) == id(elem):
        return True
    return obj.__eq__(elem)

有关更多数据,请参阅 list_contains 然后 PyObject_RichCompareBool , PyObject_RichCompare , do_richcompare

“伪执行”步骤:

c = [AA('x', np.arange(3)),
     AA('x', np.arange(3)),
     AA('y', np.arange(3))]

c[0] in c
# explain:
my_in(obj=c[0], container=c)
    # for loop:
    
    # 0-iteration:
    # elem = c[0]
    my_compare_equal(obj=c[0], elem=c[0])
        # (id(c[0]) == id(c[0])) == True
        # --> True
    bool(True)
        # True.__bool__()
        # --> True
    # --> True

c[1] in c
# explain:
my_in(obj=c[1], container=c)
    # for loop:

    # 0-iteration:
    # elem = c[0]
    my_compare_equal(obj=c[1], elem=c[0])
        # (id(c[1]) == id(c[0])) == False
        # c[1].__eq__(c[0])
            # compare tuples element by element:
            # 0-iteration:
            my_compare_equal('x', 'x') == True
            # 1-iteration:
            my_compare_equal(np.arange(3), np.arange(3))
                # (id(np.arange(3)) == id(np.arange(3))) == False
                # np.arange(3).__eq__(np.arange(3))
                # --> np.ndarray([True, True, True])
            bool(np.ndarray([True, True, True]))
                # np.ndarray([True, True, True]).__bool__()
                    raise ValueError("The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()")

c[2] in c
# explain:
my_in(obj=c[2], container=c)
    # for loop:

    # 0-iteration:
    # elem = c[0]
    my_compare_equal(obj=c[2], elem=c[0])
        # (id(c[2]) == id(c[0])) == False
        # c[2].__eq__(c[0])
            # compare tuples element by element:
            # 0-iteration:
            my_compare_equal('y', 'x') == False
            # --> False
        # --> False

    # 1-iteration:
    # analogiusly as 0-iteration:
    my_compare_equal(obj=c[2], elem=c[1])
        # --> False
    
    # 2-iteration:
    my_compare_equal(obj=c[2], elem=c[2])
        # (id(c[2]) == id(c[2])) == True
        # --> True
    # --> True