Python: ¿es una mala forma generar excepciones dentro de __init__?
128
¿Se considera mala forma de hacer excepciones dentro __init__? Si es así, ¿cuál es el método aceptado para arrojar un error cuando ciertas variables de clase se inicializan como Noneo de un tipo incorrecto?
En C, es una mala forma generar una excepción en el destructor, pero el constructor debería estar bien.
Calyth
66
@Calyth, te refieres a C ++ - no hay constructores ni destructores en C.
Alex Martelli
44
... o excepciones, para el caso.
Matt Wilding
@Calyth: lol, por favor elimine esa declaración sin sentido hecha por un error tipográfico inocente ;-)
lpapp
44
@lpapp sí. C ++. FML Y no pude editar ese comentario. Entonces, Internet documentará mi idiotez;)
Calyth
Respuestas:
159
Elevar excepciones dentro __init__()está absolutamente bien. No hay otra buena manera de indicar una condición de error dentro de un constructor, y hay muchos cientos de ejemplos en la biblioteca estándar donde construir un objeto puede generar una excepción.
La clase de error a plantear, por supuesto, depende de usted. ValueErrores mejor si el constructor pasó un parámetro no válido.
Las excepciones más utilizadas en constructor son ValueErrory TypeError.
Denis Otkidach
9
Solo señalando que __init__no es el constructor, es el intializador. Es posible que desee editar la línea No hay otra buena manera de indicar una condición de error dentro de un constructor, ..
Haris
26
Es cierto que la única forma correcta de indicar un error en un constructor es generar una excepción. Es por eso que en C ++ y en otros lenguajes orientados a objetos que se han diseñado teniendo en cuenta la seguridad de la excepción, no se llama al destructor si se produce una excepción en el constructor de un objeto (lo que significa que la inicialización del objeto está incompleta). Este no suele ser el caso en los lenguajes de secuencias de comandos, como Python. Por ejemplo, el siguiente código arroja un AttributeError si socket.connect () falla:
La razón es que se llama al destructor del objeto incompleto después de que el intento de conexión ha fallado, antes de que se haya inicializado el atributo de flujo. No debe evitar arrojar excepciones de los constructores, solo digo que es difícil escribir código seguro de excepciones en Python. Algunos desarrolladores de Python evitan usar destructores por completo, pero eso es otro tema de debate.
Esta respuesta es realmente útil. No solo se trata de la "luz verde", sino que se menciona un ejemplo con el "destructor".
lpapp
Su código de Python falla __del__porque está mal escrito. Tendría exactamente el mismo problema si lo hiciera this->p_socket->close()en un destructor en C ++. En C ++, no haría eso, dejaría que el objeto miembro se destruya a sí mismo. Haz lo mismo en python.
Por el contrario, una de las cosas por las que se sabe que las excepciones funcionan bien, en lugar de devolver códigos de error, es que los constructores no pueden devolver los códigos de error . Entonces, al menos en lenguajes como C ++, generar excepciones es la única forma de señalar errores.
>>> f = file("notexisting.txt")Traceback(most recent call last):File"<stdin>", line 1,in<module>IOError:[Errno2]No such file or directory:'notexisting.txt'
Además, realmente no veo ninguna razón por la que deba considerarse una mala forma.
Realmente no hay otra forma de indicar que algo salió mal en la inicialización de un objeto que no sea generar una excepción.
En la mayoría de las clases de programas donde el estado de una clase depende totalmente de las entradas a esa clase, podríamos esperar que se genere algún tipo de ValueError o TypeError.
Las clases con efectos secundarios (p. Ej., Una red o gráficos) pueden generar un error en init si (por ejemplo) el dispositivo de red no está disponible o no se puede escribir en el objeto del lienzo. Esto me parece razonable porque a menudo quieres saber sobre las condiciones de falla lo antes posible.
Elevar errores desde init es inevitable en algunos casos, pero hacer demasiado trabajo en init es un mal estilo. Debería considerar hacer una fábrica o una pseudo-fábrica, un método de clase simple que devuelve un objeto configurado.
Respuestas:
Elevar excepciones dentro
__init__()
está absolutamente bien. No hay otra buena manera de indicar una condición de error dentro de un constructor, y hay muchos cientos de ejemplos en la biblioteca estándar donde construir un objeto puede generar una excepción.La clase de error a plantear, por supuesto, depende de usted.
ValueError
es mejor si el constructor pasó un parámetro no válido.fuente
ValueError
yTypeError
.__init__
no es el constructor, es el intializador. Es posible que desee editar la línea No hay otra buena manera de indicar una condición de error dentro de un constructor, ..Es cierto que la única forma correcta de indicar un error en un constructor es generar una excepción. Es por eso que en C ++ y en otros lenguajes orientados a objetos que se han diseñado teniendo en cuenta la seguridad de la excepción, no se llama al destructor si se produce una excepción en el constructor de un objeto (lo que significa que la inicialización del objeto está incompleta). Este no suele ser el caso en los lenguajes de secuencias de comandos, como Python. Por ejemplo, el siguiente código arroja un AttributeError si socket.connect () falla:
La razón es que se llama al destructor del objeto incompleto después de que el intento de conexión ha fallado, antes de que se haya inicializado el atributo de flujo. No debe evitar arrojar excepciones de los constructores, solo digo que es difícil escribir código seguro de excepciones en Python. Algunos desarrolladores de Python evitan usar destructores por completo, pero eso es otro tema de debate.
fuente
__del__
porque está mal escrito. Tendría exactamente el mismo problema si lo hicierathis->p_socket->close()
en un destructor en C ++. En C ++, no haría eso, dejaría que el objeto miembro se destruya a sí mismo. Haz lo mismo en python.No veo ninguna razón para que sea una mala forma.
Por el contrario, una de las cosas por las que se sabe que las excepciones funcionan bien, en lugar de devolver códigos de error, es que los constructores no pueden devolver los códigos de error . Entonces, al menos en lenguajes como C ++, generar excepciones es la única forma de señalar errores.
fuente
La biblioteca estándar dice:
Además, realmente no veo ninguna razón por la que deba considerarse una mala forma.
fuente
Debería pensar que es el caso perfecto para la
ValueError
excepción incorporada .fuente
Estoy de acuerdo con todo lo anterior.
Realmente no hay otra forma de indicar que algo salió mal en la inicialización de un objeto que no sea generar una excepción.
En la mayoría de las clases de programas donde el estado de una clase depende totalmente de las entradas a esa clase, podríamos esperar que se genere algún tipo de ValueError o TypeError.
Las clases con efectos secundarios (p. Ej., Una red o gráficos) pueden generar un error en init si (por ejemplo) el dispositivo de red no está disponible o no se puede escribir en el objeto del lienzo. Esto me parece razonable porque a menudo quieres saber sobre las condiciones de falla lo antes posible.
fuente
Elevar errores desde init es inevitable en algunos casos, pero hacer demasiado trabajo en init es un mal estilo. Debería considerar hacer una fábrica o una pseudo-fábrica, un método de clase simple que devuelve un objeto configurado.
fuente