2010-08-23 10 views
17

Existe-t-il un moyen de vérifier si deux objets ont les mêmes valeurs, à l'exception de parcourir leurs attributs et de comparer manuellement leurs valeurs?Comparaison de deux objets

+0

Voir [cette question similaire] (http://stackoverflow.com/ questions/390250/elegant-ways-to-support-equivalence-égalité-in-python-classes) – GreenMatt

Répondre

8

solutions de Kington fonctionne si @ Joe il y a un __dict__ (certains objets, y compris builtins, n'ont pas) et __eq__ œuvres pour toutes les valeurs des deux dicts (a __eq__ des exceptions mayraise mal écrites, etc.). Mais c'est horriblement antipathique. Il ne gère pas correctement les sous-types nominaux ... beaucoup moins les sous-types structurels (c'est-à-dire les types que vous pouvez utiliser en place/pour le typage du canard). Ne faites pas cela.

Mais généralement, vous êtes mieux avec une méthode personnalisée __eq__ qui compare seulement certains attributs qui sont importants. Par exemple. Rational ne devrait comparer que le numérateur et le dénominateur, rien de plus.

+2

"certaines comparaisons sans signification peuvent soulever des exceptions": non, ceci s'applique uniquement aux comparaisons impliquant un ordre - vérifiant si 'a' est égal à' b' (ie, 'a == b', exprimé ou implicite) ** jamais ** causes exceptions (sauf si vous codez délibérément une classe bizarre remplaçant '__eq__' dans le seul but de provoquer de telles exceptions ;-). IOW, la comparaison pour l'égalité/inégalité est ** jamais ** "sans signification". –

+0

@Alex Ou à moins que quelqu'un d'autre code une telle classe. Les classes mal écrites se produisent assez fréquemment. Mais, delnan semblait impliquer que certains types intégrés se comportaient de cette façon, ce qui est en effet incorrect. –

+0

Oui, les builtins ne le font pas. Désolé si c'est lu comme ça. – delnan

-4

object1.__dict__ == object2.__dict__ devrait être tout ce dont vous avez besoin, je pense ...

Edit: vars(object1) == vars(object2) est peut-être un peu plus pythonique, bien que @delnan fait un point valide sur les objets (par exemple int s) qui n'ont pas __dict__. Je ne suis pas d'accord qu'une coutume __eq__ est une meilleure approche pour les cas simples, bien que ... Parfois, ça ne vaut pas la peine d'aller au-delà de la saleté rapide et sale, si rapide et sale fait exactement ce dont vous avez besoin, i.m.h.o.

+8

Toucher '__dict__' directement est fondamentalement toujours faux. – habnabit

+2

@Aaron, je serais d'accord que la modification de '__dict__' directement est fondamentalement toujours fausse ... Je ne serais pas d'accord que la lecture directe soit fondamentalement toujours fausse. Peut-être que "vars" est un peu plus clair, bien que ... –

+3

non, la lecture est fondamentalement toujours erronée. Il contourne le protocole descripteur, sans compter qu'il repose sur un détail d'implémentation. – habnabit

6

Pour disserter sur la réponse de 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

Vous pouvez comparer namedtuple directement.
Sinon, vous devez définir soit vos propres comparaisons riches __eq__ et peut-être __ne__
ou votre propre __cmp__

voir le datamodel pour plus d'infos

Questions connexes