try print pass exceptions example error custom catch and all python exception exception-handling error-handling try-catch

python - print - ¿Por qué “excepto: pasar” es una mala práctica de programación?



try and catch exception python (15)

¿Por qué “excepto: pasar” es una mala práctica de programación?

¿Por qué es esto malo?

try: something except: pass

Esto detecta todas las excepciones posibles, incluidas GeneratorExit , KeyboardInterrupt y SystemExit , que son excepciones que probablemente no tiene intención de detectar. Es lo mismo que atrapar BaseException .

try: something except BaseException: pass

Older versiones anteriores de la documentación dicen :

Dado que cada error en Python genera una excepción, el uso de except: puede hacer que muchos errores de programación parezcan problemas de tiempo de ejecución, lo que dificulta el proceso de depuración.

Jerarquía de excepciones de Python

Si atrapa 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 ?:

BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError +-- EOFError +-- ImportError +-- ModuleNotFoundError +-- LookupError | +-- IndexError | +-- KeyError +-- MemoryError +-- NameError | +-- UnboundLocalError +-- OSError | +-- BlockingIOError | +-- ChildProcessError | +-- ConnectionError | | +-- BrokenPipeError | | +-- ConnectionAbortedError | | +-- ConnectionRefusedError | | +-- ConnectionResetError | +-- FileExistsError | +-- FileNotFoundError | +-- InterruptedError | +-- IsADirectoryError | +-- NotADirectoryError | +-- PermissionError | +-- ProcessLookupError | +-- TimeoutError +-- ReferenceError +-- RuntimeError | +-- NotImplementedError | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError +-- SystemError +-- TypeError +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning

No hagas esto

Si está utilizando esta forma de manejo de excepciones:

try: something except: # don''t just do a bare except! pass

Entonces no podrás interrumpir tu bloque de something con Ctrl-C. Su programa pasará por alto todas las excepciones posibles dentro del bloque de código de try .

Aquí hay otro ejemplo que tendrá el mismo comportamiento indeseable:

except BaseException as e: # don''t do this either - same as bare! logging.info(e)

En su lugar, intente capturar 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:

try: foo = operation_that_includes_int(foo) except ValueError as e: if fatal_condition(): # You can raise the exception if it''s bad, logging.info(e) # but if it''s fatal every time, raise # you probably should just not catch it. else: # Only catch exceptions you are prepared to handle. foo = 0 # Here we simply assign foo to 0 and continue.

Explicación adicional con otro ejemplo.

Es posible que lo esté haciendo porque ha estado raspando la web y ha estado recibiendo, por ejemplo, un UnicodeError , pero debido a que ha utilizado la captura de excepciones más amplia, su código, que puede tener otras fallas fundamentales, intentará ejecutarse hasta el final, desperdiciando ancho de banda, tiempo de procesamiento, desgaste de su equipo, falta de memoria, recopilación de datos de 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 podrían aparecer de forma 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.

A menudo veo comentarios sobre otras preguntas de desbordamiento de pila sobre cómo se desalienta el uso de except: pass . ¿Por qué es esto malo? A veces simplemente no me importa cuáles son los errores, y quiero simplemente continuar con el código.

try: something except: pass

¿Por qué está usando un bloque de except: pass mal? ¿Qué lo hace malo? ¿Es el hecho de que pass un error o de que except algún error?


Como bien adivinaste, hay dos caras: detectar cualquier error al no especificar el tipo de excepción después de la except , y simplemente pasarlo sin realizar ninguna acción.

Mi explicación es "un poco" más larga, así que tl; dr se reduce a esto:

  1. No atrapes ningún error . Siempre especifique de qué excepciones está preparado para recuperarse y solo capture esas.
  2. Trate de evitar pasar a excepción de los bloques . A menos que se desee explícitamente, esto no suele ser una buena señal.

Pero vamos a entrar en detalles:

No atrapes ningún error

Cuando usa un bloque de try , generalmente hace esto porque sabe que existe la posibilidad de que se lance una excepción. Como tal, también tiene una idea aproximada de qué se puede romper y qué excepción se puede lanzar. En tales casos, atrapa 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 int() que podría generar un ValueError . Puede recuperarlo fácilmente simplemente pidiéndole al usuario que lo intente de nuevo, por lo que capturar el ValueError y ValueError al usuario otra vez 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 alternativa, por lo que el archivo no es exactamente necesario. Entonces, la captura de un FileNotFoundError y la simple aplicación de 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. Como tal, en cada caso, solo explícitamente except esa cierta excepción.

Sin embargo, si tuviéramos que atrapar todo , entonces, además de las 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 debe recuperarse de

Tomemos el ejemplo del archivo de configuración de arriba. En caso de que falte un archivo, solo aplicamos nuestra configuración predeterminada, y en un momento posterior podríamos decidir guardar automáticamente la configuración (por lo que la próxima vez, el archivo existe). Ahora imagine que obtenemos un IsADirectoryError o un PermissionError lugar. En tales casos, probablemente no queremos continuar; Todavía podríamos aplicar nuestra configuración predeterminada, pero luego no podremos guardar el archivo. Y es probable que el usuario también tenga una configuración personalizada, por lo que es probable que no se desee utilizar los valores predeterminados. Por lo tanto, nos gustaría informarle al usuario de inmediato, y probablemente abortar la ejecución del programa también. Pero eso no es algo que queramos hacer en algún lugar profundo dentro de una pequeña parte del código; Esto es algo de importancia a nivel de la aplicación, por lo que debe manejarse en la parte superior, así que deje que la excepción crezca.

Otro ejemplo simple también se menciona en el documento de expresiones de Python 2 . Aquí, existe un error tipográfico simple en el código que hace que se rompa. Como NameErrors todas las excepciones, también NameErrors y SyntaxErrors . Ambos son errores que nos suceden a todos mientras programamos; 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 perderemos ayuda para depurarlos correctamente.

Pero también hay excepciones más peligrosas para las cuales no estamos preparados. Por ejemplo, SystemError suele ser algo que sucede raramente y que realmente no podemos planear; significa que hay algo más complicado, algo que probablemente nos impide continuar con la tarea actual.

En cualquier caso, es muy improbable que esté preparado para todo en una parte del código a pequeña escala, por lo que realmente es donde debe detectar las excepciones para las que está preparado. Algunas personas sugieren, al menos, capturar Exception ya que no incluirá elementos como SystemExit y KeyboardInterrupt que, por diseño , terminan su aplicación, pero yo diría que esto todavía es demasiado inespecífico. Solo hay un lugar donde personalmente acepto la Exception captura o cualquier excepción, y eso es en un único controlador de excepción de nivel de aplicación global que tiene el único propósito de registrar cualquier excepción para la que no estemos preparados. De esa manera, todavía 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 de que No volverá a suceder. Pero, por supuesto, eso solo funciona si alguna vez detectamos las excepciones que ya esperábamos, por lo que las que no esperábamos naturalmente explotarán.

Trate de evitar pasar excepto bloques.

Al capturar explícitamente una pequeña selección de excepciones específicas, hay muchas situaciones en las que estaremos bien al no hacer nada. En tales casos, solo con except SomeSpecificException: pass está bien. Sin embargo, la mayoría de las veces este no es el caso, ya que es probable que necesitemos algún código relacionado con el proceso de recuperación (como se mencionó anteriormente). Esto puede ser, por ejemplo, algo que vuelva a intentar la acción, o para configurar un valor predeterminado en su lugar.

Sin embargo, si ese no es el caso, por ejemplo, porque nuestro código ya está estructurado para que se repita hasta que tenga éxito, entonces simplemente aprobar es lo suficientemente bueno. Tomando nuestro ejemplo de arriba, podríamos pedirle al usuario que ingrese un número. Como sabemos que a los usuarios les gusta no 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 intentando hasta que no se produce ninguna excepción, no necesitamos hacer nada especial en el bloque de excepción, por lo que está bien. Pero, por supuesto, se 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, solo pasar una except 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, intente evitar simplemente la aprobación. Si realmente no hay nada que hacer (y está absolutamente seguro de ello), entonces considere agregar un comentario por qué ese es el caso; de lo contrario, expanda el bloque de excepción para incluir realmente algún código de recuperación.

except: pass

El peor ofensor es la combinación de ambos. Esto significa que estamos captando cualquier error de buena gana, aunque no estamos preparados para ello y tampoco hacemos nada al respecto. Al menos desea registrar el error y también es probable que vuelva a subirlo para que finalice la aplicación (es poco probable que pueda continuar como siempre después de un error de memoria). El simple hecho de pasar no solo mantendrá la aplicación algo viva (dependiendo de dónde se encuentre, por supuesto), sino que también desechará toda la información, haciendo que sea imposible descubrir el error, lo cual es especialmente cierto si usted no es el que lo está descubriendo.

Así que la conclusión es: Cumpla únicamente las excepciones que realmente esperas y estás preparado para recuperar; todos los demás son probablemente errores que deberías corregir, o algo para lo que no estás preparado de todos modos. Pasar excepciones específicas está bien si realmente no necesitas hacer algo al respecto. En todos los demás casos, es solo un signo de presunción y de ser perezoso. Y definitivamente quieres arreglar eso.


Debe usar al menos, except Exception: para evitar la captura de excepciones del sistema como SystemExit o KeyboardInterrupt . Aquí hay un link a los documentos.

En general, debe definir explícitamente las excepciones que desea capturar, para evitar la captura de excepciones no deseadas. Debes saber qué excepciones ignoras .


Ejecutar su pseudo código literalmente no da ningún error:

try: something except: pass

como si fuera una pieza de código perfectamente válida, en lugar de lanzar un NameError . Espero que esto no sea lo que quieres.


El principal problema aquí es que ignora todos y cualquier error: se ha agotado la memoria, la CPU está ardiendo, 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 silenciosamente y se rompe en formas completamente impredecibles que nadie puede depurar.

Es por eso que debe limitarse a ignorar específicamente solo algunos errores y dejar pasar el resto.


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. Solo deja que el error termine tu programa, no hay nada que puedas hacer.

  • Boneheaded : Su propio fallo, probablemente debido a un error de supervisión, error o programación. Deberías arreglar el error. De nuevo, seguramente no debes ignorar y continuar.

  • Exógena : puede esperar estos errores en situaciones excepcionales, como el archivo no encontrado o la conexión terminada . Debes 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.


En mi opinión, los errores tienen una razón para aparecer, que mi sonido es estúpido, pero así es como es. La buena programación solo genera errores cuando tienes 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 adelante", por lo que si desea tener una declaración de excepción vacía, siéntase libre de hacerlo, pero para un buen programa habrá ser una parte faltante. 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 vuelvan a ocurrir (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 correctamente. Por ejemplo, una NetworkException puede indicar una conexión de red rota y el programa no puede enviar / recibir datos en los siguientes pasos del programa.

Pero el uso de un bloque de aprobación para un solo bloque de ejecución es válido, porque aún se diferencia entre los tipos de excepciones, por lo que si coloca todos los bloques de excepción en uno, no estará vacío:

try: #code here except Error1: #exception handle1 except Error2: #exception handle2 #and so on

Se puede reescribir de esa manera:

try: #code here except BaseException as e: if isinstance(e, Error1): #exception handle1 elif isinstance(e, Error2): #exception handle2 ... else: raise

Por lo tanto, incluso varios bloques de excepción con declaraciones de aprobación pueden generar un código, cuya estructura maneja tipos especiales de excepciones.


En pocas palabras, si se produce una excepción o error, algo está mal. Puede que no sea algo muy incorrecto, pero crear, lanzar y capturar errores y excepciones por el simple hecho de usar sentencias goto no es una buena idea, y rara vez se hace. El 99% de las veces, hubo un problema en alguna parte.

Los problemas deben ser tratados. Al igual que en la vida, en la programación, si dejas los problemas solos 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 ti y vuelva a atacar en el futuro, debes: 1) eliminarlo y limpiar el desorden después, o 2) contenerlo y limpiar el desorden después.

Simplemente ignorar las excepciones y los errores y dejarlos así es una buena manera de experimentar fugas de memoria, conexiones de base de datos sobresalientes, bloqueos innecesarios de permisos de archivos, etc.

En raras ocasiones, el problema es tan minúsculo, trivial y, además de necesitar un bloque de captura de prueba, es auto-contenido , por lo que no hay problema para limpiarlo después. Estas son las únicas ocasiones en que esta buena 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 mezquino y perdonable, y algo así como los intentos de reintento o los mensajes especiales no valen la complejidad ni la retención del hilo.

En mi empresa, la regla es casi siempre hacer algo en un bloque catch, y si no haces nada, siempre debes colocar un comentario con una buena razón por la que no. Nunca debe pasar o dejar un bloque de captura vacío cuando haya algo que hacer.


Entonces, ¿qué salida produce este código?

fruits = [ ''apple'', ''pear'', ''carrot'', ''banana'' ] found = False try: for i in range(len(fruit)): if fruits[i] == ''apple'': found = true except: pass if found: print "Found an apple" else: print "No apples in list"

Ahora imagine el try , except bloque es cientos de líneas de llamadas a una jerarquía de objetos complejos, y se llama en el centro del árbol de llamadas del gran programa. Cuando el programa sale mal, ¿dónde empiezas a buscar?


La construcción except:pass esencialmente silencia todas y cada una de las condiciones excepcionales que surgen mientras se ejecuta el código cubierto en el bloque try: .

Lo que hace esta mala práctica es que generalmente no es lo que realmente quieres. Más a menudo, aparece una condición específica que desea silenciar, y except:pass es un instrumento demasiado contundente. Terminará el trabajo, pero también ocultará otras condiciones de error que probablemente no haya anticipado, pero que quizás quiera tratar de alguna otra manera.

Lo que hace que esto sea particularmente importante en Python es que, según los modismos de este lenguaje, las excepciones no son necesariamente errores . A menudo se usan de esta manera, por supuesto, como en la mayoría de los idiomas. Pero Python, en particular, los ha usado ocasionalmente para implementar una ruta de salida alternativa desde algunas tareas de código que en realidad no forma parte del caso de ejecución normal, pero aún se sabe que aparece de vez en cuando y puede incluso esperarse en la mayoría de los casos. SystemExit ya se ha mencionado como un ejemplo antiguo, pero el ejemplo más común en la actualidad puede ser StopIteration . El uso de excepciones de esta manera causó mucha controversia, especialmente cuando los iteradores y los generadores se introdujeron por primera vez en Python, pero finalmente prevaleció la idea.


La razón # 1 ya se ha declarado: 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, es bastante obvio para otro desarrollador qué funcionalidad debería tener el bloque ''catch''. Si no especifica una excepción, entonces necesita comentarios adicionales para explicar qué debe hacer el bloque.

(# 3) - Demuestra programación perezosa. Si usa el try / catch genérico, indica que no entiende los posibles errores de tiempo de ejecución en su programa o que no sabe qué excepciones son posibles en Python. La captura de un error específico muestra que usted comprende tanto su programa como el rango de errores que Python lanza. Es más probable que esto haga que otros desarrolladores y revisores de códigos confíen en su trabajo.


Manejar errores es muy importante en la programación. Necesitas mostrar al usuario lo que salió mal. En muy pocos casos puedes ignorar los errores. Esto es muy mala práctica de programación.


Primero, viola dos principios del Zen de Python :

  • Explícito es mejor que implícito
  • Los errores nunca deben pasar en silencio.

Lo que significa, es que intencionalmente haces que tu error pase en silencio. Además, no sabe qué evento ocurrió exactamente, porque except: pass detectará cualquier excepción.

En segundo lugar, si intentamos abstraernos del Zen de Python y hablamos en términos de cordura, deberías saber, que usar except:pass te permite conocer ni controlar tu sistema. La regla de oro es plantear una excepción, si ocurre un error, y tomar las medidas apropiadas. Si no lo sabe de antemano, qué acciones deberían ser, al menos registre el error en algún lugar (y vuelva a plantear la excepción):

try: something except: logger.exception(''Something happened'')

Pero, por lo general, si intentas atrapar alguna excepción, ¡probablemente estés haciendo algo mal!


Todos los comentarios planteados hasta ahora son válidos. Siempre que sea posible, debe especificar exactamente qué excepción desea ignorar. Siempre que sea posible, debe analizar qué causó la excepción y solo ignorar lo que quería ignorar, y no el resto. Si la excepción hace que la aplicación se "bloquee espectacularmente", entonces, porque es mucho más importante saber lo inesperado que sucedió cuando sucedió, que ocultar que el problema ocurrió alguna vez.

Con todo lo dicho, no tome ninguna práctica de programación como de suma importancia. Esto es estúpido. Siempre existe el momento y el lugar para hacer el bloque de ignorar todas las excepciones.

Otro ejemplo de importancia idiota es el uso del operador goto . Cuando estaba en la escuela, nuestro profesor nos enseñó a goto operador goto solo para mencionar que nunca lo usarás, NUNCA. No creas que la gente te dice que nunca se debe usar xyz y que no puede haber un escenario cuando sea útil. Siempre hay


>>> import this

El zen de Python, por Tim Peters

Lo bello es mejor que lo feo.
Explícito es mejor que implícito.
Lo simple es mejor que lo complejo.
Complejo es mejor que complicado.
Plano es mejor que anidado.
Lo escaso es mejor que lo denso.
La legibilidad cuenta.
Los casos especiales no son lo suficientemente especiales para romper las reglas.
Aunque la practicidad supera la pureza.
Los errores nunca deben pasar en silencio.
A menos que sea silenciado explícitamente.
Ante la ambigüedad, rechace la tentación de adivinar.
Debe haber una, y preferiblemente solo una, obvia forma de hacerlo.
Aunque esa forma puede no ser obvia al principio a menos que seas holandés.
Ahora es mejor que nunca.
Aunque nunca es a menudo mejor que ahora.
Si la implementación es difícil de explicar, es una mala idea.
Si la implementación es fácil de explicar, puede ser una buena idea.
Los espacios de nombres son una gran idea, ¡hagamos más de ellos!

Por lo tanto, aquí está mi opinión. Siempre que encuentre un error, debe hacer algo para manejarlo, es decir, escribirlo en el archivo de registro o algo más. Al menos, le informa que solía haber un error.