zerodivisionerror try print pass example error catch and python exception exception-handling try-catch

pass - try except python 3 print error



¿Es una buena práctica usar try-except-else en Python? (9)

De vez en cuando en Python, veo el bloque:

try: try_this(whatever) except SomeException as exception: #Handle exception else: return something

¿Cuál es la razón para que exista el intento, excepto el otro?

No me gusta ese tipo de programación, ya que está utilizando excepciones para realizar el control de flujo. Sin embargo, si está incluido en el idioma, debe haber una buena razón para ello, ¿no es así?

Tengo entendido que las excepciones no son errores , y que solo deben usarse para condiciones excepcionales (por ejemplo, trato de escribir un archivo en el disco y no hay más espacio, o tal vez no tengo permiso), y no para el flujo controlar.

Normalmente manejo las excepciones como:

something = some_default_value try: something = try_this(whatever) except SomeException as exception: #Handle exception finally: return something

O si realmente no quiero devolver nada si ocurre una excepción, entonces:

try: something = try_this(whatever) return something except SomeException as exception: #Handle exception


¿Cuál es la razón para que exista el intento, excepto el otro?

Un bloque de try permite manejar un error esperado. El bloque de except solo debe detectar las excepciones que está preparado para manejar. Si maneja un error inesperado, su código puede hacer lo incorrecto y ocultar errores.

Se ejecutará una cláusula else si no hubo errores, y al no ejecutar ese código en el bloque try , evitará detectar un error inesperado. Una vez más, la captura de un error inesperado puede ocultar errores.

Ejemplo

Por ejemplo:

try: try_this(whatever) except SomeException as the_exception: handle(the_exception) else: return something

La suite "try, except" tiene dos cláusulas opcionales, else y finally . Así que en realidad es try-except-else-finally .

else se evaluará solo si no hay ninguna excepción en el bloque try . Nos permite simplificar el código más complicado a continuación:

no_error = None try: try_this(whatever) no_error = True except SomeException as the_exception: handle(the_exception) if no_error: return something

por lo tanto, si comparamos un else con la alternativa (que podría crear errores), vemos que reduce las líneas de código y podemos tener una base de código más legible, más fácil de mantener y con menos errores.

finally

finally se ejecutará sin importar qué, incluso si otra línea está siendo evaluada con una declaración de retorno.

Desglosado con pseudocódigo

Podría ayudar a desglosar esto, en la forma más pequeña posible que demuestre todas las características, con comentarios. Suponga que este pseudo-código es sintácticamente correcto (pero no se puede ejecutar a menos que se definan los nombres) en una función.

Por ejemplo:

try: try_this(whatever) except SomeException as the_exception: handle_SomeException(the_exception) # Handle a instance of SomeException or a subclass of it. except Exception as the_exception: generic_handle(the_exception) # Handle any other exception that inherits from Exception # - doesn''t include GeneratorExit, KeyboardInterrupt, SystemExit # Avoid bare `except:` else: # there was no exception whatsoever return something() # if no exception, the "something()" gets evaluated, # but the return will not be executed due to the return in the # finally block below. finally: # this block will execute no matter what, even if no exception, # after "something" is eval''d but before that value is returned # but even if there is an exception. # a return here will hijack the return functionality. e.g.: return True # hijacks the return in the else clause above

Es cierto que podríamos incluir el código en el bloque else en el bloque try lugar, donde se ejecutaría si no hubiera excepciones, pero ¿y si ese código genera una excepción del tipo que detectamos? Dejarlo en el bloque try ocultaría ese error.

Queremos minimizar las líneas de código en el bloque try para evitar la captura de excepciones que no esperábamos, bajo el principio de que si nuestro código falla, queremos que falle ruidosamente. Esta es una mejor práctica

Tengo entendido que las excepciones no son errores

En Python, la mayoría de las excepciones son errores.

Podemos ver la jerarquía de excepciones usando pydoc. Por ejemplo, en Python 2:

$ python -m pydoc exceptions

o Python 3:

$ python -m pydoc builtins

Nos dará la jerarquía. Podemos ver que la mayoría de los tipos de Exception son errores, aunque Python usa algunos de ellos para cosas como la terminación for bucles ( StopIteration ). Esta es la jerarquía de Python 3:

BaseException Exception 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 StopAsyncIteration StopIteration SyntaxError IndentationError TabError SystemError TypeError ValueError UnicodeError UnicodeDecodeError UnicodeEncodeError UnicodeTranslateError Warning BytesWarning DeprecationWarning FutureWarning ImportWarning PendingDeprecationWarning ResourceWarning RuntimeWarning SyntaxWarning UnicodeWarning UserWarning GeneratorExit KeyboardInterrupt SystemExit

Un comentarista preguntó:

Supongamos que tiene un método que hace ping a una API externa y desea manejar la excepción en una clase fuera del envoltorio de la API, ¿simplemente devuelve e del método bajo la cláusula de excepción donde e es el objeto de excepción?

No, no devuelves la excepción, solo vuelve a raise con una raise simple para preservar el seguimiento de pila.

try: try_this(whatever) except SomeException as the_exception: handle(the_exception) raise

O, en Python 3, puede generar una nueva excepción y preservar el retroceso con el encadenamiento de excepciones:

try: try_this(whatever) except SomeException as the_exception: handle(the_exception) raise DifferentException from the_exception

Yo elaboro en mi respuesta aquí .


"No sé si es por ignorancia, pero no me gusta ese tipo de programación, ya que está utilizando excepciones para realizar el control de flujo".

En el mundo de Python, el uso de excepciones para el control de flujo es común y normal.

Incluso los desarrolladores del núcleo de Python usan excepciones para el control de flujo y ese estilo está fuertemente integrado en el lenguaje (es decir, el protocolo del iterador usa StopIteration para indicar la terminación del bucle).

Además, el estilo try-except-se usa para prevenir las condiciones de carrera inherentes en algunas de las construcciones de "look-before-you-leap" . Por ejemplo, probar os.path.exists da como resultado información que puede estar desactualizada en el momento en que la use. Del mismo modo, Queue.full devuelve información que puede ser obsoleta. El estilo try-except-else producirá un código más confiable en estos casos.

"Entiendo que las excepciones no son errores, solo deben usarse en condiciones excepcionales"

En algunos otros idiomas, esa regla refleja sus normas culturales como se refleja en sus bibliotecas. La "regla" también se basa en parte en consideraciones de rendimiento para esos idiomas.

La norma cultural de Python es algo diferente. En muchos casos, debe usar excepciones para control-flow. Además, el uso de excepciones en Python no ralentiza el código circundante y el código de llamada como lo hace en algunos lenguajes compilados (es decir, CPython ya implementa el código para la verificación de excepciones en cada paso, independientemente de si realmente usa las excepciones o no).

En otras palabras, entender que "las excepciones son para lo excepcional" es una regla que tiene sentido en otros idiomas, pero no para Python.

"Sin embargo, si está incluido en el lenguaje mismo, debe haber una buena razón para ello, ¿no es así?"

Además de ayudar a evitar las condiciones de carrera, las excepciones también son muy útiles para tirar de los bucles externos. Esta es una optimización necesaria en lenguajes interpretados que no tienden a tener movimiento de código invariante de bucle automático.

Además, las excepciones pueden simplificar bastante el código en situaciones comunes en las que la capacidad de manejar un problema está muy alejada de donde surgió el problema. Por ejemplo, es común tener un código de llamada de código de interfaz de usuario de nivel superior para la lógica empresarial que a su vez llama rutinas de bajo nivel. Las situaciones que surgen en las rutinas de bajo nivel (como registros duplicados para claves únicas en accesos a bases de datos) solo se pueden manejar en el código de nivel superior (como pedirle al usuario una nueva clave que no entre en conflicto con las claves existentes). El uso de excepciones para este tipo de control-flow permite que las rutinas de nivel medio ignoren completamente el problema y se desacoplen bien de ese aspecto del control de flujo.

Hay una buena publicación en el blog sobre la indispensabilidad de las excepciones aquí .

También, vea esta respuesta de desbordamiento de pila: ¿Son las excepciones realmente errores excepcionales?

"¿Cuál es la razón para que exista el intento, excepto el otro?"

La cláusula else en sí es interesante. Se ejecuta cuando no hay excepción, pero antes de la cláusula finally. Ese es su propósito principal.

Sin la cláusula else, la única opción para ejecutar código adicional antes de la finalización sería la práctica torpe de agregar el código a la cláusula try. Eso es torpe porque corre el riesgo de generar excepciones en el código que no fue diseñado para ser protegido por el bloque de prueba.

El caso de uso de ejecutar código desprotegido adicional antes de la finalización no surge muy a menudo. Por lo tanto, no espere ver muchos ejemplos en el código publicado. Es algo raro.

Otro caso de uso para la cláusula else es realizar acciones que deben ocurrir cuando no se produce una excepción y que no ocurren cuando se manejan las excepciones. Por ejemplo:

recip = float(''Inf'') try: recip = 1 / f(x) except ZeroDivisionError: logging.info(''Infinite result'') else: logging.info(''Finite result'')

Por último, el uso más común de una cláusula else en un bloque de prueba es para un poco de embellecimiento (alineación de resultados excepcionales y resultados no excepcionales en el mismo nivel de sangría). Este uso es siempre opcional y no es estrictamente necesario.


¿Es una buena práctica usar try-except-else en python?

La respuesta a esto es que depende del contexto. Si haces esto:

d = dict() try: item = d[''item''] except KeyError: item = ''default''

Demuestra que no conoces muy bien a Python. Esta funcionalidad está encapsulada en el método dict.get :

item = d.get(''item'', ''default'')

El bloque try / except es una forma mucho más abarrotada y verbalmente visual de escribir lo que puede ejecutarse de manera eficiente en una sola línea con un método atómico. Hay otros casos donde esto es cierto.

Sin embargo, eso no significa que debamos evitar todo manejo de excepciones. En algunos casos se prefiere evitar condiciones de carrera. No compruebe si existe un archivo, solo intente abrirlo y capture el IOError apropiado. En aras de la simplicidad y la legibilidad, intente encapsular esto o factorizarlo como apropiado.

Lea el Zen de Python , entienda que hay principios que están en tensión, y desconfíe del dogma que se basa demasiado en cualquiera de las declaraciones que contiene.


Cada vez que veas esto:

try: y = 1 / x except ZeroDivisionError: pass else: return y

O incluso esto:

try: return 1 / x except ZeroDivisionError: return None

Considera esto en su lugar:

import contextlib with contextlib.suppress(ZeroDivisionError): return 1 / x


Debe tener cuidado al usar el bloque finally, ya que no es lo mismo que usar un bloque else en el intento, excepto. El bloque finally se ejecutará independientemente del resultado del intento, excepto.

In [10]: dict_ = {"a": 1} In [11]: try: ....: dict_["b"] ....: except KeyError: ....: pass ....: finally: ....: print "something" ....: something

Como todos han notado, el uso del bloque else hace que su código sea más legible, y solo se ejecuta cuando no se lanza una excepción

In [14]: try: dict_["b"] except KeyError: pass else: print "something" ....:


Este es mi fragmento simple de cómo entender el bloque try-except-else-finally en Python:

def div(a, b): try: a/b except ZeroDivisionError: print("Zero Division Error detected") else: print("No Zero Division Error") finally: print("Finally the division of %d/%d is done" % (a, b))

Probemos div 1/1:

div(1, 1) No Zero Division Error Finally the division of 1/1 is done

Probemos div 1/0

div(1, 0) Zero Division Error detected Finally the division of 1/0 is done


OP, ERES CORRECTO. Lo más después de probar / excepto en Python es feo . conduce a otro objeto de control de flujo donde no se necesita ninguno:

try: x = blah() except: print "failed at blah()" else: print "just succeeded with blah"

Un equivalente totalmente claro es:

try: x = blah() print "just succeeded with blah" except: print "failed at blah()"

Esto es mucho más claro que una cláusula else. El "after" try / except no se escribe con frecuencia, por lo que se tarda un momento en averiguar cuáles son las implicaciones.

Solo porque PUEDES hacer una cosa, no significa que DEBES hacer una cosa.

Se han agregado muchas funciones a los idiomas porque alguien pensó que podría ser útil. El problema es que cuantas más funciones, menos claras y obvias son las cosas, porque la gente no suele usar esas campanas y silbidos.

Sólo mis 5 centavos aquí. Tengo que ir detrás y limpiar una gran cantidad de código escrito por los desarrolladores universitarios de primer año que piensan que son inteligentes y quieren escribir código de una manera súper ajustada y eficiente cuando eso hace que sea un desastre para tratar de leer / modificar más tarde. Voto por la legibilidad todos los días y dos veces los domingos.


Python no se suscribe a la idea de que las excepciones solo deben usarse en casos excepcionales, de hecho, el idioma es "pedir perdón, no permiso" . Esto significa que el uso de excepciones como parte rutinaria de su control de flujo es perfectamente aceptable y, de hecho, se recomienda.

Esto generalmente es bueno, ya que trabajar de esta manera ayuda a evitar algunos problemas (como un ejemplo obvio, las condiciones de carrera a menudo se evitan), y tiende a hacer que el código sea un poco más legible.

Imagina que tienes una situación en la que tomas una entrada de usuario que necesita ser procesada, pero tiene un valor predeterminado que ya está procesado. El try: ... except: ... else: ... estructura lo convierte en un código muy legible:

try: raw_value = int(input()) except ValueError: value = some_processed_value else: # no error occured value = process_value(raw_value)

Compare con cómo podría funcionar en otros idiomas:

raw_value = input() if valid_number(raw_value): value = process_value(int(raw_value)) else: value = some_processed_value

Tenga en cuenta las ventajas. No es necesario verificar que el valor sea válido y analizarlo por separado, se realizan una sola vez. El código también sigue una progresión más lógica, la ruta principal del código es primero, seguida de "si no funciona, haga esto".

El ejemplo es, naturalmente, un poco artificial, pero muestra que hay casos para esta estructura.


Vea el siguiente ejemplo que ilustra todo acerca de try-except-else-finally:

for i in range(3): try: y = 1 / i except ZeroDivisionError: print(f"/ti = {i}") print("/tError report: ZeroDivisionError") else: print(f"/ti = {i}") print(f"/tNo error report and y equals {y}") finally: print("Try block is run.")

Implementalo y ven por:

i = 0 Error report: ZeroDivisionError Try block is run. i = 1 No error report and y equals 1.0 Try block is run. i = 2 No error report and y equals 0.5 Try block is run.