¿Debo especificar siempre un tipo de excepción en las declaraciones "except"?

93

Cuando se usa PyCharm IDE, el uso de except:sin un tipo de excepción activa un recordatorio del IDE de que esta cláusula de excepción es Too broad.

¿Debería ignorar este consejo? ¿O es Pythonic especificar siempre el tipo de excepción?

Caballo gordo
fuente
Si desea obtener más información sobre esto que las respuestas, google traga excepciones. Puede hacer todo tipo de interesantes y no hacer junto a ellos. El código huele es otro.
Tony Hopkinson

Respuestas:

89

Casi siempre es mejor especificar un tipo de excepción explícita. Si usa una except:cláusula simple , puede terminar detectando excepciones distintas de las que espera detectar; esto puede ocultar errores o dificultar la depuración de programas cuando no están haciendo lo que espera.

Por ejemplo, si está insertando una fila en una base de datos, es posible que desee detectar una excepción que indique que la fila ya existe, de modo que pueda realizar una actualización.

try:
    insert(connection, data)
except:
    update(connection, data)

Si especifica un bare except:, también detectará un error de socket que indica que el servidor de la base de datos se ha caído. Es mejor detectar solo las excepciones que sepa cómo manejar; a menudo es mejor que el programa falle en el punto de la excepción que continuar pero comportarse de maneras extrañas e inesperadas.

Un caso en el que es posible que desee utilizar un except: programa básico es en el nivel superior de un programa que debe estar siempre en ejecución, como un servidor de red. Pero entonces, debe tener mucho cuidado al registrar las excepciones, de lo contrario, será imposible averiguar qué está fallando. Básicamente, solo debería haber como máximo un lugar en un programa que haga esto.

Un corolario de todo esto es que su código nunca debería funcionar raise Exception('some message')porque obliga a usar el código del cliente except:(o except Exception:que es casi tan malo). Debe definir una excepción específica para el problema que desea señalar (tal vez heredando de alguna subclase de excepción incorporada como ValueErroro TypeError). O debería generar una excepción incorporada específica. Esto permite a los usuarios de su código tener cuidado al detectar solo las excepciones que desean manejar.

babbageclunk
fuente
7
+1 Muy cierto. Aún más divertido con el ejemplo: except:también captura (entre muchas otras cosas) NameErrory AttributeError, por lo tanto, si escribe mal algo en el trybloque (por ejemplo, su función "insertar" se llama en realidad insert_oneporque alguien no valora la coherencia tanto como debería), siempre lo intenta en silencio update().
1
Entonces, ¿qué sucede cuando necesita asegurarse de que no se produzca una excepción por encima del sitio de llamada actual? Es decir, he detectado todas las excepciones específicas que puedo prever que se lanzarán, ahora debo agregar que "si esto en lo que no he pensado se lanza, necesito registrarlo antes de que mate el contexto de ejecución en ejecución" (como main())?
Adam Parkin
Ese es el tipo de situación a la que me refiero en el párrafo que comienza con 'Un caso ...'. Definitivamente es necesario a veces, pero cualquier programa debería tener un solo lugar que lo haga. Y debe tener cuidado de que quede claro en el registro lo que está sucediendo; de lo contrario, tendrá un tiempo frustrante tratando de averiguar por qué su programa no está manejando el evento / solicitud / lo que sea correctamente.
babbageclunk
3
@delnan: Peor que eso. except Exception:atrapará NameErrory AttributeErrortambién. Lo que hace que el desnudo sea except:tan malo es que captura cosas que no tienen por qué ser capturadas, por ejemplo, SystemExit(se genera cuando llamas exito sys.exit, y ahora has evitado una salida prevista) y KeyboardInterrupt(nuevamente, si el usuario golpea Ctrl-C, probablemente no quieras para seguir corriendo solo para fastidiarlos). Solo el último tiene algún sentido real de atrapar, y debe capturarse explícitamente. Al menos except Exception:deja que esos dos se propaguen normalmente.
ShadowRanger
38

No debe ignorar los consejos que le da el intérprete.

De la Guía de estilo de PEP-8 para Python:

Cuando detecte excepciones, mencione excepciones específicas siempre que sea posible en lugar de usar una cláusula except: desnuda.

Por ejemplo, use:

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

Una simple cláusula except: capturará las excepciones SystemSalir y KeyboardInterrupt, lo que hará más difícil interrumpir un programa con Control-C, y puede ocultar otros problemas. Si desea capturar todas las excepciones que señalan errores de programa, use except Exception: (bare except es equivalente a except BaseException :).

Una buena regla general es limitar el uso de cláusulas "excepto" desnudas a dos casos:

Si el manejador de excepciones imprimirá o registrará el rastreo; al menos el usuario será consciente de que se ha producido un error. Si el código necesita hacer algún trabajo de limpieza, pero luego permite que la excepción se propague hacia arriba con raise. intentar ... finalmente puede ser una mejor manera de manejar este caso.

Asheeshr
fuente
9

No específico para Python esto.

El objetivo de las excepciones es abordar el problema lo más cerca posible de donde se originó.

Por lo tanto, mantiene el código que, en circunstancias excepcionales, podría desencadenar el problema y la resolución "al lado".

El caso es que no puede conocer todas las excepciones que podría generar un fragmento de código. Todo lo que puede saber es que si se trata de una excepción de archivo no encontrado, entonces puede interceptarlo y pedirle al usuario que obtenga uno que lo haga o cancele la función.

Si intenta atrapar eso, entonces no importa qué problema haya en su rutina de archivos (solo lectura, permisos, UAC, no realmente un pdf, etc.), todos ingresarán a su archivo no encontrado, y su usuario está gritando "pero está ahí, este código es una mierda"

Ahora bien, hay un par de situaciones en las que puede captar todo, pero deben elegirse conscientemente.

Se capturan, deshacen alguna acción local (como crear o bloquear un recurso, (abrir un archivo en el disco para escribir, por ejemplo), luego lanzar la excepción nuevamente, para que se trate en un nivel superior)

El otro tú es que no te importa por qué salió mal. Impresión, por ejemplo. Es posible que tenga una trampa en general, como decir Hay algún problema con su impresora, por favor, resuélvalo y no elimine la aplicación por eso. Un vano similar si su código ejecutara una serie de tareas separadas usando algún tipo de horario, no querría que todo se muera, porque una de las tareas falló.

Nota Si hace lo anterior, no puedo recomendar algún tipo de registro de excepción, por ejemplo, intente capturar el final del registro, lo suficiente.

Tony Hopkinson
fuente
Yo diría que se trata de equilibrio. Debe detectar la excepción lo suficientemente temprano para poder recuperarse y lo suficientemente tarde para saber a dónde ir con ella. Es por eso que el manejo de excepciones de Java causa tantos estragos, porque tiene que volver a ajustar la excepción en cada paso y pierde información.
dhill
2
+1 para "no te importa por qué salió mal". Lo estoy usando en varios lugares alrededor de una sola línea de código donde analizo una fecha / hora de una URL. La biblioteca de análisis de fecha / hora de terceros no enumera todas las excepciones que puede generar (encontré OverflowError y TypeError además del ValueError estándar, pero probablemente hay más), y de todos modos realmente no me importa por qué se lanzó una excepción, solo quiero proporcionar un mensaje de error razonable al usuario diciendo que algo está mal con la fecha / hora.
Michael Rodby
3

También atraparás, por ejemplo, Control-C con eso, así que no lo hagas a menos que lo "tires" de nuevo. Sin embargo, en ese caso debería utilizar "finalmente".

Ulrich Eckhardt
fuente
3

Siempre especifique el tipo de excepción, hay muchos tipos que no quieren ponerse al día, como SyntaxError, KeyboardInterrupt, MemoryErroretc.

Pavel Anossov
fuente
2
¿Usaría except Exception:evitar los tipos anteriores que no queremos atrapar?
HorseloverFat
except Exceptionestá bien.
Ulrich Eckhardt
4
@HorseloverFat: except Exceptionatrapa SyntaxErrory MemoryErrorporque es su clase base. KeyboardInterrupt, SystemExit(planteados por sys.exit()) no se detectan (son subclases de BaseException inmediatas)
jfs
Parece que no es ideal, es mejor especificarlo con mayor precisión.
HorseloverFat
3

Aquí están los lugares donde uso excepto sin tipo

  1. creación de prototipos rápida y sucia

Ese es el uso principal en mi código para excepciones no verificadas.

  1. función main () de nivel superior, donde registro todas las excepciones no detectadas

Siempre agrego esto, para que el código de producción no derrame rastros de pila

  1. entre capas de aplicación

Tengo dos formas de hacerlo:

  • Primera forma de hacerlo: cuando una capa de nivel superior llama a una función de nivel inferior, envuelve las llamadas en excepciones escritas para manejar las excepciones de nivel inferior "superior". Pero agrego una declaración de excepción genérica para detectar excepciones de nivel inferior no controladas en las funciones de nivel inferior.

Lo prefiero de esta manera, me resulta más fácil detectar qué excepciones deberían haberse detectado correctamente: "veo" mejor el problema cuando un nivel superior registra una excepción de nivel inferior

  • Segunda forma de hacerlo: cada función de nivel superior de las capas de nivel inferior tiene su código envuelto en una excepción genérica, que captura todas las excepciones no controladas en esa capa específica.

Algunos compañeros de trabajo prefieren esta forma, ya que mantiene excepciones de nivel inferior en funciones de nivel inferior, a las que "pertenecen".

nipil
fuente
-14

Prueba esto:

try:
    #code
except ValueError:
    pass

Obtuve la respuesta de este enlace, si alguien más se encuentra con este problema , compruébelo

Mekanic
fuente