print - Si escribe pato en Python, ¿debería probar la instancia?
type python 3 (3)
Tienes una clase de Python que necesita una prueba de iguales. Python debería usar tipografía de pato pero, ¿es (mejor / más preciso) incluir o excluir una prueba de instancia en la función eq ? Por ejemplo:
class Trout(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
return isinstance(other, Trout) and self.value == other.value
El principio de "tipificación de pato" es que no te importa qué es other
, siempre que tenga un atributo de value
. Entonces, a menos que sus atributos compartan nombres con semánticas en conflicto, sugeriría hacerlo así:
def __eq__(self, other):
try:
return self.value == other.value
except AttributeError:
return False # or whatever
(Alternativamente, puede probar si other
tiene un atributo de value
, pero "es más fácil pedir perdón que obtener permiso")
El uso de isintsance()
generalmente está bien en los __eq__()
. Sin embargo, no debe devolver False
inmediatamente si falla la comprobación de isinstance()
; es mejor devolver NotImplemented
para dar a other.__eq__()
posibilidad de ser ejecutado:
def __eq__(self, other):
if isinstance(other, Trout):
return self.x == other.x
return NotImplemented
Esto será particularmente importante en las jerarquías de clases donde más de una clase define __eq__()
:
class A(object):
def __init__(self, x):
self.x = x
def __eq__(self, other):
if isinstance(other, A):
return self.x == other.x
return NotImplemented
class B(A):
def __init__(self, x, y):
A.__init__(self, x)
self.y = y
def __eq__(self, other):
if isinstance(other, B):
return self.x, self.y == other.x, other.y
return NotImplemented
Si regresara False
inmediatamente, como lo hizo en su código original, perdería la simetría entre A(3) == B(3, 4)
y B(3, 4) == A(3)
.
Usar isinstance en los métodos __eq__
es bastante común. La razón de esto es que si el método __eq__
falla, puede __eq__
un método __eq__
desde otro objeto. La mayoría de los métodos normales se llaman explícitamente, pero __eq__
se llama implícitamente, por lo que se requiere mirar antes de saltar con más frecuencia.
EDITAR (gracias por el recordatorio, Sven Marnach):
Para hacer que sea alternativo, puede devolver el singleton No implementado, como en este ejemplo:
class Trout(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
if isinstance(other, Trout):
return self.value == other.value
else:
return NotImplemented
Supongamos que una RainbowTrout
sabe cómo compararse con una Trout
o con otra RainbowTrout
, pero una Trout
solo sabe cómo compararse con una Trout
. En este ejemplo, si prueba mytrout == myrainbowtrout
, Python llamará primero mytrout.__eq__(myrainbowtrout)
, notará que falla, y luego llamará a myrainbowtrout.__eq__(mytrout)
, lo cual myrainbowtrout.__eq__(mytrout)
.