2010-08-23 29 views
17

Esiste un modo per verificare se due oggetti hanno gli stessi valori, oltre a scorrere i relativi attributi e confrontare manualmente i loro valori?Confronto di due oggetti

+0

Sede [questa domanda simile] (http://stackoverflow.com/ domande/390250/classi elegante-way-to-support-equivalence-ugality-in-python) – GreenMatt

risposta

8

soluzioni @ Joe Kington funziona se c'è un __dict__ (alcuni oggetti, tra cui i comandi incorporati, non hanno uno) e __eq__ opere per tutti i valori di entrambe le dicts (a scritti male __eq__ mayraise eccezioni ecc). Ma è orribilmente unpitonico. Non gestisce nemmeno i sottotipi nominali in modo appropriato ... molto meno sottotipi strutturali (cioè tipi che è possibile utilizzare sul posto/per la tipizzazione delle anatre). Non farlo.

Ma di solito si sta meglio con un metodo su misura __eq__ che confronta solo alcuni attributi significativi. Per esempio. Rational dovrebbe confrontare solo numeratore e denominatore, niente di più.

+2

"alcune comparazioni prive di significato possono sollevare eccezioni": no, questo vale solo per i confronti che riguardano l'ordinamento - verificare se 'a' è uguale a' b' (es. 'A == b', espresso o implicito) ** mai ** causa eccezioni (a meno che non si codifichi deliberatamente una strana classe che sovrascrive '__eq__' al solo scopo di causare tali eccezioni ;-). IOW, il confronto per l'uguaglianza/disuguaglianza è ** mai ** "privo di significato". –

+0

@Alex O a meno che qualcun altro non codifichi tale classe. Le classi scritte male compaiono piuttosto frequentemente. Ma Delnan sembrava implicare che alcuni tipi di builtin si comportassero in questo modo, il che è davvero scorretto. –

+0

Sì, i builtin non lo fanno. Scusa se legge così. Gli oggetti – delnan

-4

object1.__dict__ == object2.__dict__ dovrebbe essere tutto il necessario, credo ...

Edit: vars(object1) == vars(object2) è forse un po 'più divinatorio, anche se @delnan rende un valido punto sugli oggetti (ad esempio int i) che non hanno un __dict__. Non sono d'accordo sul fatto che un custom __eq__ rappresenti un approccio migliore per i casi semplici, anche se ... A volte non vale la pena di andare oltre il rapido e sporco, se veloce e sporco fa esattamente ciò che ti serve, i.m.h.o.

+8

Toccare direttamente '__dict__' è fondamentalmente sempre sbagliato. – habnabit

+2

@Aaron, sono d'accordo sul fatto che modificare direttamente '__dict__' è fondamentalmente sempre sbagliato ... Non sono d'accordo sul fatto che leggerlo direttamente è fondamentalmente sempre sbagliato. Forse 'vars' è un po 'più chiaro, anche se ... –

+3

no, leggere è fondamentalmente sempre sbagliato. Ignora il protocollo descrittore, per non parlare del fatto che si basa su un dettaglio di implementazione. – habnabit

6

di esporre sulla risposta di delnan:

_NOTFOUND = object() 

class Rational(object): 
    def __eq__(self, other): 
     for attr in ['numerator', 'denominator']: 
      v1, v2 = [getattr(obj, attr, _NOTFOUND) for obj in [self, other]] 
      if v1 is _NOTFOUND or v2 is _NOTFOUND: 
       return False 
      elif v1 != v2: 
       return False 
     return True 
2

È possibile confrontare direttamente namedtuple.
In caso contrario è necessario definire sia i propri confronti ricchi __eq__ ed eventualmente __ne__
o il proprio __cmp__

vedere la datamodel per ulteriori informazioni