Historia de la pregunta:
En Python, la comparación de objetos por valor se realiza a través del operador '==', que internamente llama al método eq. El comportamiento de este método por defecto se hereda de object y compara la identidad de los objetos (para la mayoría de las clases).
Problema:
Cuando queremos que las instancias de las clases personalizadas se comparen de manera significativa (por ejemplo, que dos objetos diferentes de Person con el mismo conjunto de datos sean considerados iguales), el comportamiento estándar no es suficiente: es necesario definir explícitamente cómo se realiza la comparación.
Solución:
Para cambiar el comportamiento de '==', es necesario sobrescribir el método eq en nuestra propia clase. Si la clase debe ser hashable, también será necesario sobrescribir hash.
Ejemplo de código:
class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): if not isinstance(other, Person): return NotImplemented return self.name == other.name and self.age == other.age p1 = Person("Ann", 25) p2 = Person("Ann", 25) print(p1 == p2) # True
Características clave:
¿Es la comparación '==' siempre simétrica para objetos de diferentes tipos?
No necesariamente: si el primer objeto devuelve NotImplemented, se llama a la comparación inversa. De lo contrario, puede haber asimetría.
class A: def __eq__(self, other): return True class B: pass print(A() == B()) # True print(B() == A()) # False
Si no se implementa eq, ¿cómo se compararán los objetos de una misma clase personalizada?
Se comparará la identidad (id en memoria, no los valores de los atributos).
class Foo: def __init__(self, x): self.x = x f1 = Foo(5) f2 = Foo(5) print(f1 == f2) # False
¿Se puede definir eq sin hash para objetos que deben ser claves de un diccionario?
No. Si eq se modifica, también es deseable definir hash, de lo contrario, el objeto se volverá no hashable (TypeError al usarlo como clave).
class Foo: def __eq__(self, other): return True # hash se hereda de object, pero el comportamiento será impredecible # Mejor definir explícitamente __hash__
Caso negativo
Al diseñar la clase ValueObject en el equipo, no se tuvo en cuenta que solo se implementó eq, pero no hash. Al intentar usar el objeto como clave en un diccionario o elemento de un conjunto, se produjo una excepción TypeError.
Ventajas:
Rápida implementación de comparación personalizada.
Desventajas:
Imposibilidad de utilizar objetos en conjuntos y diccionarios, dificultad para depurar.
Caso positivo
En otro proyecto, los desarrolladores implementaron claramente ambos métodos: eq y hash, siguiendo rigurosamente la regla: si dos objetos son iguales según eq, sus hashes deben coincidir.
Ventajas:
Funcionamiento correcto de las estructuras hash, comportamiento consistente, facilidad de mantenimiento.
Desventajas:
Pérdida de flexibilidad: los objetos iguales por valor son indistinguibles en contenedores hash.