2014-10-22 14 views
17

Ho il codice seguente, che mi sta facendo gratto la testa -Perché il mio oggetto viene rimosso correttamente da un elenco quando __eq__ non viene chiamato?

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

da cui si ricava il seguente risultato -

before [a, b, c, d] 
comparing a to d (False) 
comparing b to d (False) 
comparing c to d (False) 
after [a, b, c] 

Perché non eq() è l'output comparing d to d (True)?

La ragione per cui sono scimmia patching __eq__ invece di implementarlo nella mia classe Element è perché sto testando come scimmia patch funziona prima a implementare con una delle librerie che sto usando.

risposta

16

Il quarto elemento è esattamente lo stesso oggetto con l'oggetto che il codice sta passando (elements[3]).

In altre parole,

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

Quindi, non c'è bisogno di controllare l'uguaglianza, perché (?) Sono identici (stesso) uno.

Il controllo di uguaglianza si verifica se non sono identici. Ad esempio, __eq__ sarà chiamata se il codice passa un altro oggetto con lo stesso valore:

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

Grazie. Risposta molto chiara –

9

list.remove() metodo controlla prima di Python se gli oggetti sono entrambi identici altrimenti ricade metodi di confronto regolari come __eq__ in questo caso. Quindi, in questo caso, poiché entrambi gli oggetti sono identici, vengono rimossi dall'elenco.

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

Qui PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid) viene utilizzato per il confronto, e dai suoi documenti:

Se o1 e o2 sono lo stesso oggetto, PyObject_RichCompareBool() sarà tornare sempre 1 per Py_EQ e 0 per Py_NE.

+0

Grazie per aver postato uno snippet del codice sorgente di implementazione effettivo di Python. Dovrei davvero imparare a cercare lì le mie risposte. –

Problemi correlati