当__eq__未被调用时,为什么我的对象从列表中正确删除?

sel*_*lf. 17 python list python-3.x

我有以下代码,这让我抓狂 -

class Element:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name

def eq(self, other):
    print('comparing {} to {} ({})'.format(self.name, 
        other.name, 
        self.name == other.name))

    return self.name == other.name

Element.__eq__ = eq
elements = [
    Element('a'), 
    Element('b'), 
    Element('c'), 
    Element('d')    
]

print('before {}'.format(elements))
elements.remove(elements[3])
print('after {}'.format(elements))
Run Code Online (Sandbox Code Playgroud)

产生以下输出 -

before [a, b, c, d]
comparing a to d (False)
comparing b to d (False)
comparing c to d (False)
after [a, b, c]
Run Code Online (Sandbox Code Playgroud)

为什么不eq()输出comparing d to d (True)

我是猴子修补__eq__而不是简单地在我的Element课程中实现它的原因是因为我正在测试猴子修补如何在我使用其中一个库实现它之前.

fal*_*tru 16

第四个元素是与代码传递的对象完全相同的对象(elements[3]).

换句话说,

>>> elements[3] is elements[3]
True
>>> elements[3] == elements[3]
True
Run Code Online (Sandbox Code Playgroud)

所以,不需要检查相等性,因为它们(?)是相同的(相同的).

如果不相同,将进行平等检查.例如,__eq__如果代码传递具有相同值的另一个对象,则将调用它:

elements.remove(Element('d'))
Run Code Online (Sandbox Code Playgroud)


Ash*_*ary 9

Python的list.remove()方法首先检查两个对象是否相同,否则回退到常规比较方法,就像__eq__在这种情况下一样.因此,在这种情况下,由于两个对象都是相同的,因此将从列表中删除.

listremove(PyListObject *self, PyObject *v)
{
    Py_ssize_t i;

    for (i = 0; i < Py_SIZE(self); i++) {
        int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
        ...
Run Code Online (Sandbox Code Playgroud)

这里PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid)用于比较,并从其文档:

如果o1o2是同一个对象,PyObject_RichCompareBool()将始终返回1for Py_EQ0for Py_NE.