Почему мой объект правильно удален из списка, когда __eq__ не вызывается?
У меня есть следующий код, который заставляет меня почесывать голову -
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))
Что дает следующий вывод -
before [a, b, c, d]
comparing a to d (False)
comparing b to d (False)
comparing c to d (False)
after [a, b, c]
Почему не eq()
вывод comparing d to d (True)
?
Причина, по которой я заменяю обезьяны __eq__
вместо простого ее применения в классе Element
, заключается в том, что я тестирую, как работает патч обезьяны, прежде чем я реализую его с помощью одной из библиотек, которые я использую.
Ответы
Ответ 1
Четвертый элемент - это точно такой же объект с объектом, который проходит код (elements[3]
).
Другими словами,
>>> elements[3] is elements[3]
True
>>> elements[3] == elements[3]
True
Таким образом, нет необходимости проверять равенство, потому что они (?) идентичны (одни и те же).
Проверка равенства выполняется, если они не идентичны. Например, будет вызываться __eq__
, если код передает другой объект с тем же значением:
elements.remove(Element('d'))
Ответ 2
Метод 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);
...
Здесь PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid)
используется для сравнения и из его документов:
Если o1
и o2
- один и тот же объект, PyObject_RichCompareBool()
будет всегда возвращайте 1
для Py_EQ
и 0
для Py_NE
.