Vous devez implémenter la méthode __eq__
:
class MyClass:
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def __eq__(self, other):
if not isinstance(other, MyClass):
# don't attempt to compare against unrelated types
return NotImplemented
return self.foo == other.foo and self.bar == other.bar
Maintenant, il génère:
>>> x == y
True
Notez que l'implémentation __eq__
rendra automatiquement les instances de votre classe inutilisables, ce qui signifie qu'elles ne peuvent pas être stockées dans des ensembles et des dict. Si vous ne modélisez pas un type immuable (c'est-à-dire si les attributs foo
et bar
peuvent changer de valeur pendant la durée de vie de votre objet), il est recommandé de laisser vos instances comme non partageables.
Si vous modélisez un type immuable, vous devez également implémenter le hook de modèle de données __hash__
:
class MyClass:
...
def __hash__(self):
# necessary for instances to behave sanely in dicts and sets.
return hash((self.foo, self.bar))
Une solution générale, comme l'idée de parcourir __dict__
et de comparer des valeurs, n'est pas recommandée - elle ne peut jamais être vraiment générale car elles __dict__
peuvent contenir des types incomparables ou inchangeables.
NB: sachez qu'avant Python 3, vous devrez peut-être utiliser à la __cmp__
place de __eq__
. Les utilisateurs de Python 2 peuvent également vouloir implémenter __ne__
, car un comportement par défaut sensible pour l'inégalité (c'est-à-dire inverser le résultat d'égalité) ne sera pas créé automatiquement dans Python 2.
return NotImplemented
(au lieu d'éleverNotImplementedError
). Ce sujet est couvert ici: stackoverflow.com/questions/878943/…Vous remplacez les opérateurs de comparaison riches dans votre objet.
Comme ça:
la source
__eq__()
, mais seulement l' un des__lt__()
,__le__()
,__gt__()
ou__ge__()
est nécessaire en plus de cela. De cela, Python peut déduire les autres méthodes. Voirfunctools
pour plus d'informations.functools
module, mais ne fonctionne pas pour les comparateurs standard:MyObj1 != Myobj2
ne fonctionnera que si la__ne__()
méthode est implémentée.@functools.total_ordering
décorateur sur votre classe, alors comme ci-dessus, vous pouvez définir juste__eq__
et un autre et le reste sera dérivéImplémentez la
__eq__
méthode dans votre classe; quelque chose comme ça:Modifier: si vous voulez que vos objets soient égaux si et seulement s'ils ont des dictionnaires d'instance égaux:
la source
self is other
voir s'ils sont le même objet.AttributeError
. Vous devez insérer la ligneif hasattr(other, "path") and hasattr(other, "title"):
(comme ce bel exemple dans la documentation Python).En résumé:
__eq__
plutôt que__cmp__
, sauf si vous exécutez python <= 2.0 (__eq__
a été ajouté en 2.1)__ne__
(devrait être quelque chose commereturn not self.__eq__(other)
oureturn not self == other
sauf cas très spécial)Si vous souhaitez comparer avec un objet qui peut être Aucun, vous devez l'implémenter. L'interprète ne peut pas le deviner ... (voir l'exemple ci-dessous)
la source
Selon votre cas spécifique, vous pourriez faire:
Voir le dictionnaire Python à partir des champs d'un objet
la source
Avec des Dataclasses dans Python 3.7 (et supérieur), une comparaison des instances d'objet pour l'égalité est une fonctionnalité intégrée.
Un backport pour Dataclasses est disponible pour Python 3.6.
la source
Lorsque vous comparez des instances d'objets, le
__cmp__
fonction est appelée.Si l'opérateur == ne fonctionne pas pour vous par défaut, vous pouvez toujours redéfinir le
__cmp__
fonction de l'objet.Éditer:
Comme cela a été souligné, la
__cmp__
fonction est obsolète depuis la version 3.0. Au lieu de cela, vous devez utiliser les méthodes de «comparaison riche» .la source
Si vous avez affaire à une ou plusieurs classes que vous ne pouvez pas modifier de l'intérieur, il existe des moyens génériques et simples de le faire qui ne dépendent pas non plus d'une bibliothèque spécifique aux différences:
Méthode la plus simple et peu sûre pour les objets très complexes
pickle
est une bibliothèque de sérialisation très courante pour les objets Python, et sera donc capable de sérialiser à peu près n'importe quoi, vraiment. Dans l'extrait ci-dessus, je compare lestr
de sérialiséa
à celui deb
. Contrairement à la méthode suivante, celle-ci présente également l'avantage de vérifier les classes personnalisées.Le plus gros problème: en raison de méthodes de classement et de codage [de / en] spécifiques, il se
pickle
peut que le résultat ne soit pas le même pour des objets égaux , en particulier lorsqu'il s'agit d' plus complexes (par exemple, des listes d'instances de classe personnalisée imbriquées) comme vous en trouverez fréquemment dans certaines bibliothèques tierces. Pour ces cas, je recommanderais une approche différente:Méthode complète et sûre pour tout objet
Vous pouvez écrire une réflexion récursive qui vous donnera des objets sérialisables, puis comparer les résultats
Peu importe ce que sont vos objets, une égalité profonde est assurée pour fonctionner
Peu importe le nombre de comparables
Mon cas d'utilisation était de vérifier une profonde égalité parmi un ensemble diversifié de modèles d'apprentissage automatique déjà formés dans les tests BDD. Les modèles appartenaient à un ensemble diversifié de bibliothèques tierces. La mise en œuvre
__eq__
comme les autres réponses suggèrent certainement que ce n'était pas une option pour moi.Couvrant toutes les bases
Vous pouvez être dans un scénario où une ou plusieurs des classes personnalisées comparées n'ont pas d'
__dict__
implémentation . Ce n'est pas commun par tous les moyens, mais il est le cas d'un sous - type au sein du classificateur Forêt aléatoire de sklearn:<type 'sklearn.tree._tree.Tree'>
. Traitez ces situations au cas par cas - par exemple, spécifiquement , j'ai décidé de remplacer le contenu du type affecté par le contenu d'une méthode qui me donne des informations représentatives sur l'instance (dans ce cas, la__getstate__
méthode). Pour tel, l'avant-dernier rangbase_typed
est devenuEdit: pour des raisons d'organisation, j'ai remplacé les deux dernières lignes de
base_typed
withreturn dict_from(obj)
, et implémenté une réflexion vraiment générique pour accueillir des bibliothèques plus obscures (je vous regarde, Doc2Vec)N'oubliez pas qu'aucune des méthodes ci-dessus ne donne
True
pour différents objets avec les mêmes paires clé-valeur mais des ordres clé / valeur différents, comme dansMais si vous le souhaitez, vous pouvez de toute façon utiliser la
sorted
méthode intégrée de Python au préalable.la source
J'ai écrit cela et l'ai placé dans un
test/utils
module de mon projet. Pour les cas où ce n'est pas une classe, il suffit de planifier ol 'dict, cela traversera les deux objets et assureraC'est gros ... ce n'est pas sexy ... mais oh boi ça marche!
Vous pouvez le nettoyer un peu en supprimant le
_assert
et en utilisant simplement ol 'assert
mais le message que vous obtenez en cas d'échec est très inutile.la source
Vous devez implémenter la méthode
__eq__
:la source
Ci-dessous fonctionne (dans mes tests limités) en effectuant une comparaison approfondie entre deux hiérarchies d'objets. Dans gère divers cas, y compris les cas où les objets eux-mêmes ou leurs attributs sont des dictionnaires.
Il s'agit d'un code très délicat, veuillez donc ajouter les cas qui pourraient ne pas fonctionner pour vous dans les commentaires.
la source
la source
Si vous souhaitez obtenir une comparaison attribut par attribut et voir si et où cela échoue, vous pouvez utiliser la compréhension de liste suivante:
L'avantage supplémentaire ici est que vous pouvez presser une ligne et entrer dans la fenêtre "Evaluer l'expression" lors du débogage dans PyCharm.
la source
J'ai essayé l'exemple initial (voir 7 ci-dessus) et cela n'a pas fonctionné en ipython. Notez que cmp (obj1, obj2) renvoie un "1" lorsqu'il est implémenté à l'aide de deux instances d'objet identiques. Curieusement, lorsque je modifie l'une des valeurs d'attribut et que je la compare, en utilisant cmp (obj1, obj2), l'objet continue de renvoyer un "1". (soupir...)
Ok, donc ce que vous devez faire est d'itérer deux objets et de comparer chaque attribut en utilisant le signe ==.
la source
L'instance d'une classe par rapport à == devient non égale. La meilleure façon est d' assigner la fonction cmp à votre classe qui fera le travail.
Si vous voulez faire une comparaison par le contenu, vous pouvez simplement utiliser cmp (obj1, obj2)
Dans votre cas cmp (doc1, doc2) Il retournera -1 si le contenu est le même.
la source