A menudo veo comentarios sobre otras preguntas de Stack Overflow sobre cómo except: pass
se desaconseja el uso de . ¿Por qué es esto malo? A veces simplemente no me importa cuáles son los errores, y solo quiero continuar con el código.
try:
something
except:
pass
¿Por qué es except: pass
malo usar un bloque? ¿Qué lo hace malo? ¿Es el hecho de que estoy pass
en un error o que tengo except
algún error?
logging
módulo en el nivel DEBUG para evitar que se transmitan en producción, pero manténgalos disponibles en el desarrollo.Respuestas:
Como adivinó correctamente, tiene dos lados: detectar cualquier error al no especificar ningún tipo de excepción después
except
y simplemente pasarlo sin realizar ninguna acción.Mi explicación es "un poco" más larga, así que, tl; dr se descompone en esto:
Pero entremos en detalles:
No atrape ningún error
Cuando usa un
try
bloque, generalmente lo hace porque sabe que existe la posibilidad de que se produzca una excepción. Como tal, también tiene una idea aproximada de lo que se puede romper y qué excepción se puede lanzar. En tales casos, detecta una excepción porque puede recuperarse positivamente de ella. Eso significa que está preparado para la excepción y tiene algún plan alternativo que seguirá en caso de esa excepción.Por ejemplo, cuando le pide al usuario que ingrese un número, puede convertir la entrada usando lo
int()
que podría elevar aValueError
. Puede recuperarlo fácilmente simplemente pidiéndole al usuario que lo intente nuevamente, por lo que atraparloValueError
y solicitarle nuevamente sería un plan apropiado. Un ejemplo diferente sería si desea leer alguna configuración de un archivo, y ese archivo no existe. Debido a que es un archivo de configuración, es posible que tenga alguna configuración predeterminada como respaldo, por lo que el archivo no es exactamente necesario. Por lo tanto, capturarFileNotFoundError
y simplemente aplicar la configuración predeterminada sería un buen plan aquí. Ahora, en ambos casos, tenemos una excepción muy específica que esperamos y tenemos un plan igualmente específico para recuperarnos de ella. Como tal, en cada caso, explícitamente soloexcept
ese cierto excepción.Sin embargo, si tuviéramos que atrapar todo , entonces, además de esas excepciones de las que estamos preparados para recuperarnos, también existe la posibilidad de que obtengamos excepciones que no esperábamos y de las cuales no podemos recuperarnos; o no debería recuperarse de.
Tomemos el ejemplo del archivo de configuración de arriba. En caso de que falte un archivo, simplemente aplicamos nuestra configuración predeterminada, y podríamos decidir en un momento posterior guardar automáticamente la configuración (por lo que la próxima vez, el archivo existe). Ahora imagina que tenemos un
IsADirectoryError
, o unPermissionError
en lugar. En tales casos, probablemente no queremos continuar; aún podríamos aplicar nuestra configuración predeterminada, pero luego no podremos guardar el archivo. Y es probable que el usuario también pretendiera tener una configuración personalizada, por lo que probablemente no se desee utilizar los valores predeterminados. Por lo tanto, nos gustaría informarle al usuario de inmediato, y probablemente también abortar la ejecución del programa. Pero eso no es algo que queremos hacer en algún lugar dentro de una pequeña parte del código; Esto es algo de importancia a nivel de aplicación, por lo que debe manejarse en la parte superior, así que deje que la excepción brote.Otro ejemplo simple también se menciona en el documento de modismos de Python 2 . Aquí, existe un error tipográfico simple en el código que hace que se rompa. Debido a que estamos cogiendo cada excepción, que también capturan
NameError
s ySyntaxError
s . Ambos son errores que nos ocurren a todos durante la programación; y ambos son errores que no queremos incluir al enviar el código. Pero debido a que también los detectamos, ni siquiera sabremos que ocurrieron allí y perdemos cualquier ayuda para depurarlo correctamente.Pero también hay excepciones más peligrosas para las cuales no estamos preparados. Por ejemplo, SystemError suele ser algo que ocurre raramente y que realmente no podemos planificar; significa que está sucediendo algo más complicado, algo que probablemente nos impide continuar con la tarea actual.
En cualquier caso, es muy poco probable que esté preparado para todo en una parte del código a pequeña escala, por lo que es allí donde solo debería detectar las excepciones para las que está preparado. Algunas personas sugieren al menos atrapar,
Exception
ya que no incluirá cosas comoSystemExit
yKeyboardInterrupt
que, por diseño , terminarán su aplicación, pero diría que esto todavía es demasiado inespecífico. Solo hay un lugar donde personalmente acepto la capturaException
o cualquieraexcepción, y eso está en un único controlador de excepciones de nivel de aplicación global que tiene el único propósito de registrar cualquier excepción para la que no estábamos preparados. De esa manera, aún podemos retener tanta información sobre excepciones inesperadas, que luego podemos usar para extender nuestro código para manejarlas explícitamente (si podemos recuperarnos de ellas) o, en caso de un error, crear casos de prueba para asegurarnos No volverá a suceder. Pero, por supuesto, eso solo funciona si alguna vez detectamos las excepciones que ya estábamos esperando, por lo que las que no esperábamos surgirán naturalmente.Trate de evitar pasar, excepto los bloques
Al capturar explícitamente una pequeña selección de excepciones específicas, hay muchas situaciones en las que estaremos bien simplemente no haciendo nada. En tales casos, solo tener
except SomeSpecificException: pass
está bien. Sin embargo, la mayoría de las veces, este no es el caso, ya que probablemente necesitemos algún código relacionado con el proceso de recuperación (como se mencionó anteriormente). Esto puede ser, por ejemplo, algo que vuelve a intentar la acción, o para configurar un valor predeterminado.Sin embargo, si ese no es el caso, por ejemplo, porque nuestro código ya está estructurado para repetirse hasta que tenga éxito, simplemente pasar es suficiente. Tomando nuestro ejemplo de arriba, podríamos pedirle al usuario que ingrese un número. Como sabemos que a los usuarios no les gusta hacer lo que les pedimos, podríamos ponerlo en un bucle en primer lugar, para que se vea así:
Debido a que seguimos intentándolo hasta que no se produce ninguna excepción, no necesitamos hacer nada especial en el bloque excepto, por lo que está bien. Pero, por supuesto, uno podría argumentar que al menos queremos mostrarle al usuario algún mensaje de error para decirle por qué tiene que repetir la entrada.
Sin embargo, en muchos otros casos, el solo hecho de pasar
except
una señal es una señal de que no estábamos realmente preparados para la excepción que estamos detectando. A menos que esas excepciones sean simples (comoValueError
oTypeError
), y la razón por la que podemos aprobar es obvia, trate de evitarla. Si realmente no hay nada que hacer (y está absolutamente seguro de ello), considere agregar un comentario de por qué ese es el caso; de lo contrario, expanda el bloque excepto para incluir algún código de recuperación.except: pass
Sin embargo, el peor delincuente es la combinación de ambos. Esto significa que estamos captando cualquier error voluntariamente, aunque no estamos absolutamente preparados para ello y tampoco hacemos nada al respecto. Usted al menos desea registrar el error y también es probable que vuelves a subir todavía para terminar la aplicación (que es poco probable que pueda continuar de manera normal después de un MemoryError). Sin embargo, el simple hecho de pasar no solo mantendrá la aplicación un tanto activa (dependiendo de dónde se encuentre, por supuesto), sino que también arrojará toda la información, lo que hará imposible descubrir el error, lo cual es especialmente cierto si usted no es el que lo descubre.
Entonces, la conclusión es: Capture solo las excepciones que realmente espera y está preparado para recuperarse; todos los demás probablemente sean errores que debe corregir o algo para lo que no está preparado de todos modos. Pasar excepciones específicas está bien si realmente no necesita hacer algo al respecto. En todos los demás casos, es solo un signo de presunción y de ser flojo. Y definitivamente quieres arreglar eso.
fuente
except
, pero luego llamanraise
sin argumentos para continuar dejando que la excepción brote, terminando la aplicación. Me gusta: ianbicking.org/blog/2007/09/re-raising-exceptions.html . Parece una excepción sólida a la regla sobre no usar la mantaexcept
.raise
. Sin embargo, generalmente solo haría esto en algunas ubicaciones dentro de su aplicación para registrar la excepción.El principal problema aquí es que ignora todo y cualquier error: sin memoria, la CPU se está quemando, el usuario quiere parar, el programa quiere salir, Jabberwocky está matando a los usuarios.
Esto es demasiado. En tu cabeza, estás pensando "Quiero ignorar este error de red". Si algo inesperado sale mal, entonces su código continúa en silencio y se rompe de una manera completamente impredecible que nadie puede depurar.
Es por eso que debe limitarse a ignorar específicamente solo algunos errores y dejar pasar el resto.
fuente
Ejecutar su pseudocódigo literalmente ni siquiera da ningún error:
como si fuera un código perfectamente válido, en lugar de lanzar un
NameError
. Espero que esto no sea lo que quieres.fuente
Esto detecta todas las excepciones posibles, incluidas
GeneratorExit
,KeyboardInterrupt
ySystemExit
, que son excepciones que probablemente no pretendes detectar. Es lo mismo que atraparBaseException
.Las versiones anteriores de la documentación dicen :
Jerarquía de excepciones de Python
Si captura una clase de excepción principal, también captura todas sus clases secundarias. Es mucho más elegante capturar solo las excepciones que está preparado para manejar.
Aquí está la jerarquía de excepciones de Python 3 : ¿realmente quieres atraparlos a todos ?:
No hagas esto
Si está utilizando esta forma de manejo de excepciones:
Entonces no podrás interrumpir tu
something
bloqueo con Ctrl-C. Su programa pasará por alto todas las excepciones posibles dentro deltry
bloque de código.Aquí hay otro ejemplo que tendrá el mismo comportamiento indeseable:
En su lugar, intente detectar solo la excepción específica que sabe que está buscando. Por ejemplo, si sabe que puede obtener un error de valor en una conversión:
Explicación adicional con otro ejemplo
Puede que lo estés haciendo porque has estado raspando la web y te han estado diciendo, un
UnicodeError
pero debido a que ha utilizado la captura de excepciones más amplia, su código, que puede tener otros defectos fundamentales, intentará ejecutarse hasta su finalización, desperdiciando ancho de banda , tiempo de procesamiento, desgaste de su equipo, falta de memoria, recopilación de datos basura, etc.Si otras personas le piden que complete para que puedan confiar en su código, entiendo que me siento obligado a manejar todo. Pero si está dispuesto a fallar ruidosamente a medida que se desarrolla, tendrá la oportunidad de corregir problemas que pueden aparecer de manera intermitente, pero que serían errores costosos a largo plazo.
Con un manejo de errores más preciso, su código puede ser más robusto.
fuente
Entonces, aquí está mi opinión. Siempre que encuentre un error, debe hacer algo para manejarlo, es decir, escribirlo en el archivo de registro u otra cosa. Al menos, le informa que solía haber un error.
fuente
Debe usar al menos
except Exception:
para evitar la captura de excepciones del sistema comoSystemExit
oKeyboardInterrupt
. Aquí hay un enlace a los documentos.En general, debe definir explícitamente las excepciones que desea capturar, para evitar la captura de excepciones no deseadas. Debe saber qué excepciones ignora .
fuente
Primero, viola dos principios del Zen de Python :
Lo que significa es que intencionalmente hace que su error pase en silencio. Además, no sabe qué evento ocurrió exactamente, porque
except: pass
detectará cualquier excepción.En segundo lugar, si tratamos de abstraernos del Zen de Python y hablar en términos de cordura justa, debes saber que usarlo
except:pass
te deja sin conocimiento y control en tu sistema. La regla general es generar una excepción, si ocurre un error, y tomar las medidas apropiadas. Si no sabe de antemano, qué acciones deberían ser, al menos registre el error en alguna parte (y mejor vuelva a plantear la excepción):Pero, por lo general, si intenta detectar alguna excepción, ¡probablemente esté haciendo algo mal!
fuente
La
except:pass
construcción esencialmente silencia todas y cada una de las condiciones excepcionales que surgen mientrastry:
se ejecuta el código cubierto en el bloque.Lo que hace que esta mala práctica sea que generalmente no es lo que realmente quieres. Más a menudo, surge una condición específica que desea silenciar, y
except:pass
es demasiado un instrumento contundente. Hará el trabajo, pero también enmascarará otras condiciones de error que probablemente no haya anticipado, pero que muy bien quiera tratar de alguna otra manera.Lo que hace que esto sea particularmente importante en Python es que, por las expresiones idiomáticas de este lenguaje, las excepciones no son necesariamente errores . A menudo se usan de esta manera, por supuesto, al igual que en la mayoría de los idiomas. Pero Python en particular los ha usado ocasionalmente para implementar una ruta de salida alternativa de algunas tareas de código que no es realmente parte del caso de ejecución normal, pero aún se sabe que aparece de vez en cuando e incluso se puede esperar en la mayoría de los casos.
SystemExit
ya se ha mencionado como un viejo ejemplo, pero el ejemplo más común hoy en día puede serStopIteration
. El uso de excepciones de esta manera causó mucha controversia, especialmente cuando los iteradores y generadores se presentaron por primera vez a Python, pero finalmente prevaleció la idea.fuente
La razón # 1 ya se ha indicado: oculta errores que no esperaba.
(# 2) - Hace que su código sea difícil de leer y entender para otros. Si detecta una excepción FileNotFoundException cuando intenta leer un archivo, entonces es bastante obvio para otro desarrollador qué funcionalidad debería tener el bloque 'catch'. Si no especifica una excepción, necesita comentarios adicionales para explicar qué debe hacer el bloque.
(# 3) - Demuestra una programación perezosa. Si usa el try / catch genérico, indica que no comprende los posibles errores de tiempo de ejecución en su programa o que no sabe qué excepciones son posibles en Python. Detectar un error específico muestra que comprende tanto su programa como el rango de errores que arroja Python. Es más probable que esto haga que otros desarrolladores y revisores de código confíen en su trabajo.
fuente
Entonces, ¿qué salida produce este código?
Ahora imagine que el bloque
try
-except
es cientos de líneas de llamadas a una jerarquía de objetos complejos, y se llama a sí mismo en medio del árbol de llamadas del programa grande. Cuando el programa sale mal, ¿dónde comienzas a buscar?fuente
En general, puede clasificar cualquier error / excepción en una de tres categorías :
Fatal : No es tu culpa, no puedes evitarlos, no puedes recuperarte de ellos. Ciertamente no debe ignorarlos y continuar, y dejar su programa en un estado desconocido. Simplemente deje que el error termine su programa, no hay nada que pueda hacer.
Deshonesto : su propia culpa, muy probablemente debido a un descuido, error o error de programación. Deberías arreglar el error. Una vez más, sin duda no debe ignorar y continuar.
Exógeno : puede esperar estos errores en situaciones excepcionales, como archivos no encontrados o conexión terminada . Debe manejar explícitamente estos errores, y solo estos.
En todos los casos
except: pass
solo dejará su programa en un estado desconocido, donde puede causar más daño.fuente
En pocas palabras, si se produce una excepción o error, algo está mal. Puede que no sea algo muy malo, pero crear, arrojar y capturar errores y excepciones solo por el uso de declaraciones goto no es una buena idea, y rara vez se hace. El 99% del tiempo, hubo un problema en alguna parte.
Los problemas deben ser resueltos. Al igual que en la vida, en la programación, si dejas los problemas en paz y tratas de ignorarlos, no desaparecen solos muchas veces; en cambio se hacen más grandes y se multiplican. Para evitar que un problema crezca en usted y golpee nuevamente más adelante en el camino, 1) lo elimina y limpia el desorden después, o 2) lo contiene y limpia el desorden después.
Simplemente ignorar excepciones y errores y dejarlos así es una buena manera de experimentar pérdidas de memoria, conexiones de bases de datos sobresalientes, bloqueos innecesarios en los permisos de archivos, etc.
En raras ocasiones, el problema es tan minúsculo, trivial y, aparte de necesitar un intento ... de captura, autocontenido , que realmente no hay ningún desastre que limpiar después. Estas son las únicas ocasiones en que esta mejor práctica no se aplica necesariamente. En mi experiencia, esto generalmente ha significado que lo que sea que esté haciendo el código es básicamente insignificante y olvidable, y algo como intentos de reintento o mensajes especiales no valen ni la complejidad ni el mantener el hilo.
En mi compañía, la regla es casi siempre hacer algo en un bloque de captura, y si no haces nada, siempre debes colocar un comentario con una muy buena razón por la que no. Nunca debe pasar o dejar un bloque de captura vacío cuando hay algo que hacer.
fuente
En mi opinión, los errores tienen una razón para aparecer, que mi sonido suena estúpido, pero así son las cosas. Una buena programación solo genera errores cuando hay que manejarlos. Además, como leí hace algún tiempo, "la declaración de aprobación es una declaración que muestra que el código se insertará más tarde", por lo que si desea tener una declaración de excepción vacía, no dude en hacerlo, pero para un buen programa habrá ser una parte que falta porque no manejas las cosas que deberías tener. Las excepciones que aparecen le dan la oportunidad de corregir los datos de entrada o de cambiar su estructura de datos para que estas excepciones no ocurran nuevamente (pero en la mayoría de los casos (excepciones de red, excepciones de entrada generales) las excepciones indican que las siguientes partes del programa no se ejecutarán bien. Por ejemplo, una excepción de red puede indicar una conexión de red interrumpida y el programa no puede enviar / recibir datos en los siguientes pasos del programa.
Pero usar un bloque de paso para un solo bloque de ejecución es válido, ya que todavía diferencia entre los tipos de excepciones, por lo que si coloca todos los bloques de excepción en uno, no está vacío:
puede reescribirse de esa manera:
Por lo tanto, incluso varios bloques de excepción con sentencias de paso pueden generar código, cuya estructura maneja tipos especiales de excepciones.
fuente
Todos los comentarios mencionados hasta ahora son válidos. Siempre que sea posible, debe especificar qué excepción exacta desea ignorar. Siempre que sea posible, debe analizar qué causó la excepción y solo ignorar lo que quiso ignorar, y no el resto. Si la excepción hace que la aplicación se "bloquee espectacularmente", entonces sea así, porque es mucho más importante saber lo inesperado que sucedió cuando sucedió, que ocultar que el problema alguna vez ocurrió.
Con todo lo dicho, no tome ninguna práctica de programación como primordial. Esto es estupido Siempre existe el momento y el lugar para hacer el bloque ignorar todas las excepciones.
Otro ejemplo de lo más idiota es el uso del
goto
operador. Cuando estaba en la escuela, nuestro profesor nos enseñó elgoto
operador solo para mencionar que nunca lo usarás. No le creas a las personas que te dicen que xyz nunca debe usarse y que no puede haber un escenario cuando sea útil. Siempre hay.fuente
El manejo de errores es muy importante en la programación. Es necesario mostrarle al usuario lo que salió mal. En muy pocos casos puede ignorar los errores. Esta es una muy mala práctica de programación.
fuente
Como aún no se ha mencionado, es mejor usar el estilo
contextlib.suppress
:Tenga en cuenta que en el ejemplo proporcionado, el estado del programa sigue siendo el mismo, se produzca o no la excepción. Es decir,
somefile.tmp
siempre se vuelve inexistente.fuente