¿Por qué devolver NotImplemented en lugar de subir NotImplementedError

283

Python tiene un singleton llamado NotImplemented.

¿Por qué alguien querría volver en NotImplementedlugar de plantear la NotImplementedErrorexcepción? ¿No hará que sea más difícil encontrar errores, como el código que ejecuta métodos no válidos?

abyx
fuente

Respuestas:

281

Esto se debe a que __lt__()los métodos de comparación relacionados se usan de manera bastante indirecta en los tipos de listas y demás. A veces, el algoritmo elegirá intentar de otra manera o elegir un ganador predeterminado. Plantear una excepción se saldría del tipo a menos que sea atrapado, mientras NotImplementedque no se eleva y puede usarse en pruebas adicionales.

http://jcalderone.livejournal.com/32837.html

Para resumir ese enlace:

" NotImplementedSeñales al tiempo de ejecución que se debe pedir a alguien más para satisfacer la operación. En la expresión a == b, si a.__eq__(b)regresa NotImplemented, luego trata de Python b.__eq__(a). Si bsabe lo suficiente para volver Trueo False, a continuación, la expresión puede tener éxito. Si no lo hace, entonces el tiempo de ejecución recurrir al comportamiento incorporado (que se basa en la identidad para ==y !=) ".

SpliFF
fuente
55
Tendría cuidado al usarlo, ya que este enlace señala cerca del final del documento.
Jason Coon
16
Cuando el intérprete de Python verifica si a.__eq__(b)NotImplemented devuelto, ¿no podría capturar NotImplementedError con la misma facilidad (y luego llamar b.__eq__(a)o lo que sea)?
Veky
24
@Veky. Elevar una excepción probablemente tenga una sobrecarga mayor. Cualquier sobrecarga en una operación de clasificación se ampliará según el tamaño de la lista, por lo que incluso si la diferencia fuera muy pequeña, tendría sentido encontrar una implementación más rápida. Tampoco desea salir de sus bucles y volver a ingresarlos, lo que requeriría una implementación de prueba / captura.
SpliFF
3
Para el primer punto, una solución aún más rápida sería sintetizar automáticamente lt como gt invertido, en lugar de llamar siempre a algo que devolverá NotImplemented, y Python no hace eso. No creo que la velocidad sea la razón aquí. Y por el segundo, no entiendo lo que estás diciendo: el retorno requerirá tanto rompimiento de bucles como aumento. De hecho, puede imaginar que return genere una excepción de retorno especial, que siempre se encuentra en el alcance de la llamada.
Veky
2
>> "ampliado por el tamaño de la lista" Al menos, a menos que tenga una clasificación O (n) que el mundo debería conocer.
Jonathan Hartley
107

Porque tienen diferentes casos de uso.

Citando los documentos (Python 3.6):

No se ha implementado

debe ser devuelto por los métodos especiales binarios (por ejemplo __eq__(), __lt__(), __add__(), __rsub__(), etc.) para indicar que la operación no se lleva a cabo con respecto al otro tipo

excepción NotImplementedError

[...] En las clases base definidas por el usuario, los métodos abstractos deberían generar esta excepción cuando requieren clases derivadas para anular el método, o mientras se desarrolla la clase para indicar que la implementación real aún necesita ser agregada.

Vea los enlaces para más detalles.

Paolo
fuente
Esta debería ser la respuesta aceptada. Es incluso más fuerte que los casos de uso, es una indicación de intención: el que tiene un Error al final del nombre indica que se ha producido un Error (porque algo no está implementado), el otro no es un error sino "correcto" comportamiento. Lo compararía con la diferencia entre devolver NaN o aumentar un ValueError.
Korone hace
13

Una razón es el rendimiento. En una situación como comparaciones ricas, donde podría realizar muchas operaciones en poco tiempo, establecer y manejar muchas excepciones podría llevar mucho más tiempo que simplemente devolver un NotImplementedvalor.

RichieHindle
fuente