Python try-else

¿Cuál es el uso previsto de la cláusula else opcional de la instrucción try ?

Las instrucciones en el bloque else se ejecutan si la ejecución cae fuera de la parte inferior del try , si no hubo una excepción. Honestamente, nunca he encontrado una necesidad.

Sin embargo, las notas de manejo de excepciones :

El uso de la cláusula else es mejor que agregar código adicional a la cláusula try porque evita la captura accidental de una excepción que no fue generada por el código protegido por la statement try … except.

Por lo tanto, si tiene un método que podría, por ejemplo, lanzar un IOError y desea detectar las excepciones que genera, pero hay algo más que desea hacer si la primera operación tiene éxito, y no desea capturar un IOError de esa operación, podrías escribir algo como esto:

  try: operation_that_can_throw_ioerror() except IOError: handle_the_exception_somehow() else: # we don't want to catch the IOError if it's raised another_operation_that_can_throw_ioerror() finally: something_we_always_need_to_do() 

Si acaba de poner another_operation_that_can_throw_ioerror() después de operation_that_can_throw_ioerror , la except detectará los errores de la segunda llamada. Y si lo pones después de todo el bloque try , siempre se ejecutará, y no hasta después del finally . El else te permite asegurarte

  1. la segunda operación solo se ejecuta si no hay excepción,
  2. se ejecuta antes del bloque finally , y
  3. cualquier IOError s que plantea no está atrapado aquí

Hay una gran razón para usar else : estilo y legibilidad. En general, es una buena idea mantener un código que pueda causar excepciones cerca del código que trata con ellos. Por ejemplo, compara estos:

 try: from EasyDialogs import AskPassword # 20 other lines getpass = AskPassword except ImportError: getpass = default_getpass 

y

 try: from EasyDialogs import AskPassword except ImportError: getpass = default_getpass else: # 20 other lines getpass = AskPassword 

La segunda es buena cuando la except no puede regresar antes o volver a lanzar la excepción. De ser posible, habría escrito:

 try: from EasyDialogs import AskPassword except ImportError: getpass = default_getpass return False # or throw Exception('something more descriptive') # 20 other lines getpass = AskPassword 

Nota: La respuesta copia del duplicado recientemente publicado aquí , por lo tanto, todo esto “AskPassword”.

Un uso: probar algún código que debería generar una excepción.

 try: this_should_raise_TypeError() except TypeError: pass except: assert False, "Raised the wrong exception type" else: assert False, "Didn't raise any exception" 

(Este código debe resumirse en una prueba más genérica en la práctica).

Python try-else

¿Cuál es el uso previsto de la cláusula else opcional de la instrucción try?

Resumen

La instrucción else ejecuta si no hay excepciones y si no es interrumpida por una return , continue o break .

Las otras respuestas pierden esa última parte.

De los documentos:

La cláusula else opcional se ejecuta cuando el control fluye fuera del final de la cláusula try . *

(Bolding añadido.) Y la nota al pie lee:

* Actualmente, el control “fluye fuera del final”, excepto en el caso de una excepción o la ejecución de una return de return , continue o break .

Requiere al menos una cláusula de excepción ( vea la gramática ). Así que realmente no es “try-else”, es “try-except-else (-finally)”, siendo el else (y finally ) opcional.

El tutorial de Python elabora sobre el uso previsto:

La sentencia try … except tiene una cláusula else opcional, que, cuando está presente, debe seguir todas las cláusulas excepto. Es útil para el código que debe ejecutarse si la cláusula try no genera una excepción. Por ejemplo:

 for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close() 

El uso de la cláusula else es mejor que agregar código adicional a la cláusula try porque evita la captura accidental de una excepción que no fue generada por el código protegido por la statement try … except.

Ejemplo que diferencia el código else versus el siguiente bloque try

Si maneja un error, el bloque else no se ejecutará. Por ejemplo:

 def handle_error(): try: raise RuntimeError('oops!') except RuntimeError as error: print('handled a RuntimeError, no big deal.') else: print('if this prints, we had no error!') # won't print! print('And now we have left the try block!') # will print! 

Y ahora,

 >>> handle_error() handled a RuntimeError, no big deal. And now we have left the try block! 

Me parece muy útil cuando tienes que hacer una limpieza que se debe hacer, incluso si hay una excepción:

 try: data = something_that_can_go_wrong() except Exception as e: # yes, I know that's a bad way to do it... handle_exception(e) else: do_stuff(data) finally: clean_up() 

Try-except-else es ideal para combinar el patrón EAFP con la escritura de pato :

 try: cs = x.cleanupSet except AttributeError: pass else: for v in cs: v.cleanup() 

Podrías pensar que este código ingenuo está bien:

 try: for v in x.cleanupSet: v.clenaup() except AttributeError: pass 

Esta es una excelente manera de ocultar accidentalmente errores graves en su código. Escribí la limpieza allí, pero el AttributeError que me dejaría saber está siendo tragado. Peor aún, ¿qué pasaría si lo hubiera escrito correctamente, pero el método de limpieza se pasaba de vez en cuando a un tipo de usuario que tenía un atributo mal llamado, lo que provocaba que fallara silenciosamente a mitad de camino y dejaba un archivo sin cerrar? Buena suerte depurando esa.

Si bien no puede pensar en un uso en este momento, puede apostar que tiene que haber un uso para él. Aquí hay una muestra poco imaginativa:

Con else :

 a = [1,2,3] try: something = a[2] except: print "out of bounds" else: print something 

Sin else

 try: something = a[2] except: print "out of bounds" if "something" in locals(): print something 

Aquí tienes la variable something definido si no se produce ningún error. Puede eliminar esto fuera del bloque try , pero luego requiere un poco de detección desordenada si se define una variable.

De errores y excepciones # Manejar excepciones – docs.python.org

La sentencia try ... except tiene una cláusula else opcional, que, cuando está presente, debe seguir todas las cláusulas excepto. Es útil para el código que debe ejecutarse si la cláusula try no genera una excepción. Por ejemplo:

 for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close() 

El uso de la cláusula else es mejor que agregar código adicional a la cláusula try porque evita la captura accidental de una excepción que no fue generada por el código protegido por la statement try … except.

Hay un buen ejemplo de try-else en PEP 380 . Básicamente, se trata de hacer un manejo de excepciones diferente en diferentes partes del algoritmo.

Es algo como esto:

 try: do_init_stuff() except: handle_init_suff_execption() else: try: do_middle_stuff() except: handle_middle_stuff_exception() 

Esto le permite escribir el código de manejo de excepciones más cerca de donde ocurre la excepción.

En cuanto a la referencia de Python , parece que else se ejecuta después de un try cuando no hay excepción. La cláusula else opcional se ejecuta cuando el control fluye fuera del final de la cláusula try. 2 Las excepciones en la cláusula else no son manejadas por las cláusulas de excepción anteriores.

Dive into python tiene un ejemplo en el que, si entiendo correctamente, en el bloque try intentan importar un módulo, cuando esto falla, se obtiene una excepción y un enlace por defecto, pero cuando funciona, tiene la opción de entrar en el bloque else y enlazar lo que se requiere. (ver enlace para el ejemplo y explicación).

Si intentas hacer un trabajo en el bloque catch , podría lanzar otra excepción: supongo que ahí es donde el bloque else es útil.

Eso es. El bloque ‘else’ de una cláusula try-except existe para el código que se ejecuta cuando (y solo cuando) la operación intentada tiene éxito. Puede ser utilizado, y puede ser abusado.

 try: fp= open("configuration_file", "rb") except EnvironmentError: confdata= '' # it's ok if the file can't be opened else: confdata= fp.read() fp.close() # your code continues here # working with (possibly empty) confdata 

Personalmente, me gusta y lo uso cuando sea apropiado. Agrupa semánticamente enunciados.

La mayoría de las respuestas parecen concentrarse en por qué no podemos simplemente poner el material en la cláusula else en la cláusula try. La pregunta else en la statement de prueba … ¿para qué sirve específicamente el por qué el código de la cláusula else no puede ir después del bloque try en sí mismo, y esa pregunta se confunde con esta, pero no veo una respuesta clara a esa pregunta? aquí. Siento que https://stackoverflow.com/a/3996378/1503120 responde de manera excelente a esa pregunta. También he intentado dilucidar los diversos significados de las distintas cláusulas en https://stackoverflow.com/a/22579805/1503120 .

Quizás un uso podría ser:

 #debug = [] def debuglog(text, obj=None): " Simple little logger. " try: debug # does global exist? except NameError: pass # if not, don't even bother displaying except: print('Unknown cause. Debug debuglog().') else: # debug does exist. # Now test if you want to log this debug message # from caller "obj" try: if obj in debug: print(text) # stdout except TypeError: print('The global "debug" flag should be an iterable.') except: print('Unknown cause. Debug debuglog().') def myfunc(): debuglog('Made it to myfunc()', myfunc) debug = [myfunc,] myfunc() 

Tal vez esto te lleve también a un uso.

A menudo puede existir un bloque else para complementar la funcionalidad que se produce en todos los bloques except .

 try: test_consistency(valuable_data) except Except1: inconsistency_type = 1 except Except2: inconsistency_type = 2 except: # Something else is wrong raise else: inconsistency_type = 0 """ Process each individual inconsistency down here instead of inside the except blocks. Use 0 to mean no inconsistency. """ 

En este caso, inconsistency_type se establece en cada bloque excepto, por lo que ese comportamiento se complementa en el caso de no error en else .

Por supuesto, estoy describiendo esto como un patrón que puede aparecer en su propio código algún día. En este caso específico, simplemente establece inconsistency_type en 0 antes del bloque try todos modos.

He encontrado el try: ... else: construye útil en la situación en la que estás ejecutando consultas de base de datos y registrando los resultados de esas consultas en una base de datos separada del mismo tipo / tipo. Digamos que tengo muchos subprocesos de trabajo, todas las consultas de bases de datos de manejo enviadas a una cola

 #in a long running loop try: query = queue.get() conn = connect_to_db(
) curs = conn.cursor() try: curs.execute(") except DBError: logconn = connect_to_db() logcurs = logconn.cursor() logcurs.execute(") logcurs = logconn.cursor() logcurs.execute("

Por supuesto, si puede distinguir entre las posibles excepciones que podrían lanzarse, no tiene que usar esto, pero si el código que reactjs a una pieza de código exitosa puede lanzar la misma excepción que la pieza exitosa, y no puede simplemente Deje pasar la segunda excepción posible, o regrese inmediatamente después de tener éxito (lo que mataría el hilo en mi caso), entonces esto es útil.

Aquí hay otro lugar donde me gusta usar este patrón:

  while data in items: try data = json.loads(data) except ValueError as e: log error else: # work on the `data` 

Supongamos que su lógica de progtwigción depende de si un diccionario tiene una entrada con una clave determinada. Puede probar el resultado de dict.get(key) utilizando if... else... construct, o puede hacer:

 try: val = dic[key] except KeyError: do_some_stuff() else: do_some_stuff_with_val() 

Uno de los escenarios de uso que se me ocurren son las excepciones impredecibles, que pueden ser evitadas si lo intentas de nuevo. Por ejemplo, cuando las operaciones en el bloque de prueba involucran números aleatorios:

 while True: try: r = random.random() some_operation_that_fails_for_specific_r(r) except Exception: continue else: break 

Pero si la excepción se puede predecir, siempre debe elegir la validación de antemano sobre una excepción. Sin embargo, no todo puede predecirse, por lo que este patrón de código tiene su lugar.

He encontrado else útil para tratar con un archivo de configuración posiblemente incorrecto:

 try: value, unit = cfg['lock'].split() except ValueError: msg = 'lock monitoring config must consist of two words separated by white space' self.log('warn', msg) else: # get on with lock monitoring if config is ok 

Una excepción que lee la configuración de lock deshabilita la supervisión de locking y ValueErrors registra un mensaje de advertencia útil.

El else: bloque es confuso y (casi) inútil. También es parte de las declaraciones for y while .

En realidad, incluso en una statement if , la else: puede ser abusada de una manera verdaderamente terrible creando errores que son muy difíciles de encontrar.

Considera esto.

  if a < 10: # condition stated explicitly elif a > 10 and b < 10: # condition confusing but at least explicit else: # Exactly what is true here? # Can be hard to reason out what condition is true 

Piensa dos veces en else: Generalmente es un problema. Evítelo, excepto en una statement if e incluso entonces considere documentar la condición else para hacerlo explícito.