182 votos

Elegantes maneras de apoyar la equivalencia ("igualdad") en las clases de Python

Cuando la escritura de clases personalizadas, es a menudo importante para permitir la equivalencia por medio de la == y != operadores de. En Python, esto es posible mediante la aplicación de la __eq__ y __ne__ métodos especiales, respectivamente. La forma más sencilla que he encontrado para hacer esto es la siguiente método:

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)

¿Sabe usted de lo más elegante manera de hacer esto? ¿Sabes de algún particular desventajas de utilizar el método de comparación de __dict__s?

Nota: Un poco de aclaración--cuando __eq__ y __ne__ son indefinidos, usted encontrará que este comportamiento:

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

Es decir, a == b evalúa False porque realmente corre a is b, una prueba de identidad (es decir, "Es a el mismo objeto como b?").

Cuando __eq__ y __ne__ están definidos, usted encontrará que este comportamiento (que es el que nos interesa):

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

141voto

Algorias Puntos 1144

Tienes que tener cuidado con la herencia:

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

Compruebe los tipos más estrictamente, así:

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

Además, su enfoque funcionará bien, eso es lo que allí son métodos especiales para.

119voto

cdleary Puntos 18869

La forma en que describes es la manera que siempre lo hice. Puesto que es totalmente genérico, siempre puedes romper esa funcionalidad en una clase de mixin y heredar en clases donde usted quiere esa funcionalidad.

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

8voto

John Mee Puntos 12004

No es una respuesta directa, pero parecía lo suficientemente relevantes para ser colgada en como se guarda un poco de verbose tedio en alguna ocasión. Cortar en línea recta desde el docs...


functools.total_ordering(cls)

Dada una clase que define uno o más ricos de comparación de métodos de ordenación, esta clase de decorador de suministros para el resto. Esto simplifica el esfuerzo involucrados en la especificación de todos los posibles rica operaciones de comparación:

La clase debe definir uno de los lt(), le(), gt(), o ge(). Además, la clase debe proporcionar una eq() método.

De nuevo en la versión 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()))

8voto

Vasil Puntos 11172

Usted no tiene que reemplazar ambos __eq__ y __ne__ se puede reemplazar sólo __cmp__ pero esto hará que una implicación directa en el resultado de==, !==, < , > y así sucesivamente.

is pruebas de la identidad de los objetos. Esto significa un is b True en el caso de que a y b tienen la referencia al mismo objeto. En python se mantenga siempre una referencia a un objeto en una variable no es el objeto real, por lo tanto, esencialmente para a es b a ser cierto que los objetos en ellos debe estar situado en la misma ubicación de memoria. Cómo y lo que es más importante ¿por qué iba a ir sobre la anulación de este comportamiento?

Edit: no sabía __cmp__ fue retirado de python 3 para evitarlo.

2voto

too much php Puntos 27983

Creo que los dos términos que buscas son de igualdad (==) e identidad (es). Por ejemplo:

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

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X