type print duck python equality duck-typing

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