Dado que Python no proporciona versiones izquierda / derecha de sus operadores de comparación, ¿cómo decide qué función llamar?
class A(object):
def __eq__(self, other):
print "A __eq__ called"
return self.value == other
class B(object):
def __eq__(self, other):
print "B __eq__ called"
return self.value == other
>>> a = A()
>>> a.value = 3
>>> b = B()
>>> b.value = 4
>>> a == b
"A __eq__ called"
"B __eq__ called"
False
Esto parece llamar a ambas __eq__
funciones.
Estoy buscando el árbol de decisión oficial.
fuente
__eq__
solo en la instancia de algún tipo no es suficiente para que == se anule?Estoy escribiendo una respuesta actualizada para Python 3 a esta pregunta.
Generalmente se entiende, pero no siempre el caso, que
a == b
invocaa.__eq__(b)
, otype(a).__eq__(a, b)
.Explícitamente, el orden de evaluación es:
b
el tipo de es una subclase estricta (no el mismo tipo) dea
tipo de y tiene__eq__
, llámelo y devuelva el valor si la comparación está implementadaa
tiene__eq__
, llámelo y devuélvalo si se implementa la comparación,__eq__
y lo tiene, luego llámelo y devuélvalo si la comparación está implementada,is
.Sabemos si no se implementa una comparación si el método regresa
NotImplemented
.(En Python 2,
__cmp__
se buscó un método, pero quedó obsoleto y se eliminó en Python 3).Probemos el comportamiento de la primera verificación por nosotros mismos dejando que B sea subclase A, lo que muestra que la respuesta aceptada es incorrecta en este aspecto:
que solo imprime
B __eq__ called
antes de regresarFalse
.¿Cómo conocemos este algoritmo completo?
Las otras respuestas aquí parecen incompletas y desactualizadas, así que actualizaré la información y le mostraré cómo podría buscar esto por sí mismo.
Esto se maneja en el nivel C.
Necesitamos mirar dos bits de código diferentes aquí: el predeterminado
__eq__
para objetos de claseobject
y el código que busca y llama al__eq__
método independientemente de si usa el predeterminado__eq__
o uno personalizado.Defecto
__eq__
Al
__eq__
buscar en los documentos relevantes de la api de C , se nos muestra que__eq__
es manejado portp_richcompare
, que en la"object"
definición de tipocpython/Objects/typeobject.c
se define enobject_richcompare
forcase Py_EQ:
.Entonces aquí, si
self == other
regresamosTrue
, de lo contrario devolvemos elNotImplemented
objeto. Este es el comportamiento predeterminado para cualquier subclase de objeto que no implemente su propio__eq__
método.Como
__eq__
se llamaLuego encontramos los documentos de la API C, PyObject_RichCompare función , que llama
do_richcompare
.Luego vemos que la
tp_richcompare
función, creada para el"object"
definición de C, es llamada pordo_richcompare
, así que veamos eso un poco más de cerca.La primera verificación en esta función es para las condiciones de los objetos que se comparan:
__eq__
método,luego llame al método del otro con los argumentos intercambiados, devolviendo el valor si se implementa. Si ese método no se implementa, continuamos ...
A continuación, vemos si podemos buscar el
__eq__
método del primer tipo y llamarlo. Siempre que el resultado no sea NotImplemented, es decir, esté implementado, lo devolvemos.De lo contrario, si no probamos el método del otro tipo y está ahí, lo probamos y, si se implementa la comparación, lo devolvemos.
Finalmente, obtenemos una alternativa en caso de que no se implemente para ninguno de los dos tipos.
El respaldo verifica la identidad del objeto, es decir, si es el mismo objeto en el mismo lugar en la memoria; esta es la misma verificación que para
self is other
:Conclusión
En una comparación, respetamos primero la implementación de la subclase de la comparación.
Luego intentamos la comparación con la implementación del primer objeto, luego con la del segundo si no fue llamado.
Finalmente, usamos una prueba de identidad para comparar la igualdad.
fuente