Como adivinó correctamente, tiene dos lados: detectar cualquier error al no especificar ningún tipo de excepción despuésexcept
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:
- No atrape ningún error . Siempre especifique de qué excepciones está preparado para recuperarse y solo capture esas.
- Trate de evitar pasar, excepto los bloques . A menos que se desee explícitamente, esto generalmente no es una buena señal.
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 a ValueError
. Puede recuperarlo fácilmente simplemente pidiéndole al usuario que lo intente nuevamente, por lo que atraparlo ValueError
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, capturar FileNotFoundError
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 solo except
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 y SyntaxError
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 como SystemExit
y KeyboardInterrupt
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 captura Exception
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í:
def askForNumber ():
while True:
try:
return int(input('Please enter a number: '))
except ValueError:
pass
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 (como ValueError
o TypeError
), 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.
logging
módulo en el nivel DEBUG para evitar que se transmitan en producción, pero manténgalos disponibles en el desarrollo.