Debe implementar el método __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
Ahora sale:
>>> x == y
True
Tenga en cuenta que la implementación __eq__
automáticamente hará que las instancias de su clase no sean compartibles, lo que significa que no se pueden almacenar en conjuntos y dictados. Si no está modelando un tipo inmutable (es decir, si los atributos foo
y el bar
valor pueden cambiar dentro de la vida útil de su objeto), se recomienda dejar sus instancias como no compartibles.
Si está modelando un tipo inmutable, también debe implementar el enlace de modelo de datos __hash__
:
class MyClass:
...
def __hash__(self):
# necessary for instances to behave sanely in dicts and sets.
return hash((self.foo, self.bar))
Una solución general, como la idea de recorrer __dict__
y comparar valores, no es aconsejable: nunca puede ser realmente general porque __dict__
puede tener tipos incomparables o no compartibles contenidos dentro.
NB: tenga en cuenta que antes de Python 3, es posible que deba usar en __cmp__
lugar de __eq__
. Los usuarios de Python 2 también pueden querer implementar __ne__
, ya que un comportamiento predeterminado sensible para la desigualdad (es decir, invertir el resultado de igualdad) no se creará automáticamente en Python 2.
return NotImplemented
(en lugar de aumentarNotImplementedError
). Ese tema está cubierto aquí: stackoverflow.com/questions/878943/…Anula los operadores de comparación enriquecidos en su objeto.
Me gusta esto:
fuente
__eq__()
, pero sólo uno de__lt__()
,__le__()
,__gt__()
, o__ge__()
se necesita, además de eso. A partir de eso, Python puede inferir los otros métodos. Verfunctools
para más información.functools
módulo, pero no para comparadores estándar:MyObj1 != Myobj2
solo funcionará si__ne__()
se implementa el método.@functools.total_ordering
decorador en su clase, luego, como se mencionó anteriormente, puede definir__eq__
uno y otro y el resto se derivaráImplemente el
__eq__
método en su clase; algo como esto:Editar: si desea que sus objetos se comparen igual si y solo si tienen diccionarios de instancias iguales:
fuente
self is other
ver si son el mismo objeto.AttributeError
. Debe insertar la líneaif hasattr(other, "path") and hasattr(other, "title"):
(como este buen ejemplo en la documentación de Python).Como un resumen :
__eq__
lugar de__cmp__
, excepto si ejecuta python <= 2.0 (__eq__
se ha agregado en 2.1)__ne__
(debe ser algo así comoreturn not self.__eq__(other)
oreturn not self == other
exceptuar caso muy especial)Si desea comparar con un objeto que puede ser Ninguno, debe implementarlo. El intérprete no puede adivinarlo ... (ver ejemplo a continuación)
fuente
Dependiendo de su caso específico, podría hacer:
Ver el diccionario Python desde los campos de un objeto
fuente
Con Dataclasses en Python 3.7 (y superior), una comparación de instancias de objetos para igualdad es una característica incorporada.
Un backport para Dataclasses está disponible para Python 3.6.
fuente
Al comparar instancias de objetos,
__cmp__
se llama a la función.Si el operador == no funciona para usted de manera predeterminada, siempre puede redefinir la
__cmp__
función para el objeto.Editar:
Como se ha señalado, la
__cmp__
función está en desuso desde 3.0. En su lugar, debe utilizar los métodos de "comparación rica" .fuente
Si está tratando con una o más clases que no puede cambiar desde adentro, existen formas genéricas y simples de hacerlo que tampoco dependen de una biblioteca específica de diferencia:
Método más fácil, inseguro para objetos muy complejos
pickle
es una lib de serialización muy común para los objetos de Python y, por lo tanto, podrá serializar prácticamente cualquier cosa. En el fragmento anterior, comparo elstr
de serializadoa
con el deb
. A diferencia del siguiente método, este tiene la ventaja de también escribir clases personalizadas de verificación.La mayor molestia: debido a la ordenación específica y a los métodos de codificación [de / en],
pickle
puede que no se obtenga el mismo resultado para objetos iguales , especialmente cuando se trata de más complejos (por ejemplo, listas de instancias de clase personalizada anidadas) como encontrará con frecuencia en algunas librerías de terceros. Para esos casos, recomendaría un enfoque diferente:Método completo, seguro para cualquier objeto
Podría escribir una reflexión recursiva que le dará objetos serializables y luego comparar resultados
Ahora no importa cuáles sean sus objetos, se garantiza que la igualdad profunda funcione
El número de comparables tampoco importa
Mi caso de uso para esto fue verificar la profunda igualdad entre un conjunto diverso de modelos de Machine Learning ya entrenados dentro de las pruebas BDD. Los modelos pertenecían a un conjunto diverso de librerías de terceros. Ciertamente, implementar
__eq__
como otras respuestas aquí sugieren que no era una opción para mí.Cubriendo todas las bases
Puede encontrarse en un escenario en el que una o más de las clases personalizadas que se comparan no tienen una
__dict__
implementación . Eso no es común, por cualquier medio, pero es el caso de un subtipo dentro clasificador Bosque aleatoria de sklearn:<type 'sklearn.tree._tree.Tree'>
. Trate estas situaciones caso por caso; por ejemplo , específicamente , decidí reemplazar el contenido del tipo afectado con el contenido de un método que me proporciona información representativa sobre la instancia (en este caso, el__getstate__
método). Para tal, la penúltima fila en sebase_typed
convirtió enEditar: por el bien de la organización, reemplacé las dos últimas líneas
base_typed
conreturn dict_from(obj)
e implementé una reflexión realmente genérica para acomodar bibliotecas más oscuras (te estoy mirando, Doc2Vec)Tenga en cuenta que ninguno de los métodos anteriores rinde
True
para diferentes objetos con los mismos pares clave-valor pero diferentes órdenes clave / valor, como enPero si lo desea, puede utilizar de
sorted
antemano el método incorporado de Python .fuente
Escribí esto y lo coloqué en un
test/utils
módulo en mi proyecto. Para los casos en los que no es una clase, solo planifique ol 'dict, esto atravesará ambos objetos y garantizaráEs grande ... no es sexy ... pero ¡oh boi, funciona!
Puede limpiarlo un poco eliminando el
_assert
y simplemente usando ol 'simple,assert
pero luego el mensaje que recibe cuando falla es muy inútil.fuente
Debe implementar el método
__eq__
:fuente
A continuación funciona (en mis pruebas limitadas) haciendo una comparación profunda entre dos jerarquías de objetos. En maneja varios casos, incluidos los casos en que los objetos mismos o sus atributos son diccionarios.
Este es un código muy complicado, así que por favor agregue cualquier caso que no funcione para usted en los comentarios.
fuente
fuente
Si desea obtener una comparación atributo por atributo y ver si falla y dónde falla, puede utilizar la siguiente lista de comprensión:
La ventaja adicional aquí es que puede exprimir una línea e ingresar en la ventana "Evaluar expresión" al depurar en PyCharm.
fuente
Intenté el ejemplo inicial (ver 7 arriba) y no funcionó en ipython. Tenga en cuenta que cmp (obj1, obj2) devuelve un "1" cuando se implementa utilizando dos instancias de objeto idénticas. Por extraño que parezca, cuando modifico uno de los valores de atributo y recompare, usando cmp (obj1, obj2) el objeto continúa devolviendo un "1". (suspiro...)
Ok, entonces lo que debes hacer es iterar dos objetos y comparar cada atributo usando el signo ==.
fuente
La instancia de una clase en comparación con == no es igual. La mejor manera es asignar la función cmp a su clase, que hará las cosas.
Si desea hacer una comparación por el contenido, simplemente puede usar cmp (obj1, obj2)
En su caso, cmp (doc1, doc2) devolverá -1 si el contenido es el mismo.
fuente