2014-10-22 1 views
17

Я следующий код, который делает меня чесать голову -Почему мой объект правильно удаляется из списка, когда __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, потому что я тестирую, как работает патч обезьяны, прежде чем я реализую его с помощью одной из библиотек, которые я использую.

ответ

16

Четвертый элемент - это точно такой же объект с объектом, который проходит код (elements[3]).

Другими словами,

>>> elements[3] is elements[3] 
True 
>>> elements[3] == elements[3] 
True 

Таким образом, нет необходимости проверять равенство, потому что они (?) Одинаковы (то же) один.

Проверка равенства выполняется, если они не идентичны. Например, __eq__ будет вызываться, если код передает другой объект с тем же значением:

elements.remove(Element('d')) 
+0

спасибо. Очень ясный ответ. –

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); 
     ... 

Здесь PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid) используется для сравнения, и от его документов:

Если o1 и o2 являются тем же объектом, PyObject_RichCompareBool() будет всегда возвращает 1 для Py_EQ и 0 для Py_NE.

+0

Благодарим за публикацию фрагмента исходного кода реализации Python. Я действительно должен научиться там искать ответы. –

Смежные вопросы