代码之家  ›  专栏  ›  技术社区  ›  nos

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

  •  1
  • nos  · 技术社区  · 5 年前

    我使用 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 .

    0 回复  |  直到 5 年前
        1
  •  2
  •   Daniel Konstantinov    5 年前

    简化:

    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
    
    推荐文章