489 votes

Élégante des façons de soutenir l'équivalence ("égalité") dans les classes Python

Lors de l'écriture de classes personnalisées, il est souvent important de permettre à l'équivalence par le biais de l' == et != opérateurs. En Python, cela est rendu possible par la mise en œuvre de l' __eq__ et __ne__ méthodes spéciales, respectivement. La façon la plus simple que j'ai trouvé à faire c'est la méthode suivante:

class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

Savez-vous de plus élégant moyen de le faire? Connaissez-vous des inconvénients à l'aide de la méthode de comparaison des __dict__s?

Remarque: Un peu de précisions--lorsqu' __eq__ et __ne__ ne sont pas définis, vous trouverez ce comportement:

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
False

C'est, a == b évalue False car il fonctionne vraiment a is b, un test d'identité (par exemple, "Est - a le même objet que l' b?").

Lors de l' __eq__ et __ne__ sont définis, vous trouverez ce comportement (qui est celui que nous sommes après):

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
True

220voto

Algorias Points 1144

Vous devez être prudent avec l'héritage:

>>> class Foo:
    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

>>> class Bar(Foo):pass

>>> b = Bar()
>>> f = Foo()
>>> f == b
True
>>> b == f
False

Types de contrôles de, plus strictement, comme ceci:

def __eq__(self, other):
    if type(other) is type(self):
        return self.__dict__ == other.__dict__
    return False

En outre, votre approche sera beau travail, c'est ce que des méthodes spéciales sont là pour.

162voto

cdleary Points 18869

La façon dont vous décrivez est la façon dont je l'ai toujours fait. Depuis qu'il est tout à fait générique, vous pouvez toujours casser cette fonctionnalité dans une classe mixin et en hériter dans les classes où vous voulez que la fonctionnalité.

class CommonEqualityMixin(object):

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
            and self.__dict__ == other.__dict__)

    def __ne__(self, other):
        return not self.__eq__(other)

class Foo(CommonEqualityMixin):

    def __init__(self, item):
        self.item = item

17voto

John Mee Points 12004

Pas de réponse directe, mais semble suffisamment pertinent pour être cloué sur car il permet d'économiser un peu d'détaillé de l'ennui à l'occasion. Coupe droite à partir de la documentation...


functools.total_ordering(cls)

Étant donné une classe définissant un ou plusieurs riches comparaison des méthodes de commande, cette classe décorateur de fournitures le reste. Cela simplifie l'effort impliqué dans la spécification de toutes les riches opérations de comparaison:

La classe doit définir l'un des lt(), le(), gt(), ou ge(). En outre, la classe doit fournir un eq() la méthode.

Nouveau dans la version 2.7

@total_ordering
class Student:
    def __eq__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) <
                (other.lastname.lower(), other.firstname.lower()))

9voto

Vasil Points 11172

Vous n'avez pas à remplacer les deux __eq__ et __ne__ vous pouvez remplacer seulement __cmp__ , mais cela fera une incidence sur le résultat de ==, !==, < , > et ainsi de suite.

is tests pour l'identité de l'objet. Cela signifie un is b True dans le cas où a et b à la fois contenir la référence à un même objet. En python que vous maintenez toujours une référence à un objet dans une variable pas l'objet réel, donc, essentiellement, pour un b est d'être vrai les objets en eux doit être situé dans le même emplacement de mémoire. Comment et surtout pourquoi voulez-vous aller sur la substitution de ce comportement?

Edit: je ne sais pas __cmp__ a été retiré de python 3 donc l'éviter.

4voto

too much php Points 27983

Je pense que les deux termes que vous recherchez sont d'égalité (==) et identité (est). Par exemple:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a == b
True       <-- a and b have values which are equal
>>> a is b
False      <-- a and b are not the same list object

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X