print - Python try-else
try except python example (20)
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.
La cláusula
else
opcional se ejecuta cuando el control fluye fuera del final de la cláusulatry
. *
(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
dereturn
,continue
obreak
.
Requiere al menos una cláusula de excepción ( vea la gramática ). Entonces realmente no es "try-else", es "try-except-else (-finally)", con el else
(y finally
) siendo 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 declaración try ... except.
Ejemplo de diferenciación de lo else
frente al código que sigue al 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!
¿Cuál es el uso previsto de la cláusula else
opcional de la instrucción try
?
A menudo puede existir un bloque else
para complementar la funcionalidad que se produce en cada bloque 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 el 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.
A pesar de que no puedes pensar en un uso en este momento, puedes 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.
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`
De errores y excepciones # Manejar excepciones - docs.python.org
La sentencia
try ... except
tiene una cláusulaelse
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 declaración try ... except.
El else:
bloque es confuso y (casi) inútil. También es parte de las declaraciones for
y while
.
En realidad, incluso en una declaración 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 declaración if
e incluso luego considere documentar la condición else
para hacerlo explícito.
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 excepciones en la cláusula else no son manejadas por las cláusulas de excepción anteriores.
2 tiene un ejemplo en el que, si entiendo correctamente, en el bloque try intentan importar un módulo, cuando eso 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.
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.
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 se copió de un duplicado recientemente publicado here , por lo tanto, todo esto "AskPassword".
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
desactiva la supervisión de bloqueo y ValueErrors registra un mensaje de advertencia útil.
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(<main db>)
curs = conn.cursor()
try:
curs.execute("<some query on user input that may fail even if sanitized">)
except DBError:
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of failed query")
logcurs.close()
logconn.close()
else:
#we can''t put this in main try block because an error connecting
#to the logging DB would be indistinguishable from an error in
#the mainquery
#We can''t put this after the whole try: except: finally: block
#because then we don''t know if the query was successful or not
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of successful query")
logcurs.close()
logconn.close()
#do something in response to successful query
except DBError:
#This DBError is because of a problem with the logging database, but
#we can''t let that crash the whole thread over what might be a
#temporary network glitch
finally:
curs.close()
conn.close()
#other cleanup if necessary like telling the queue the task is finished
Por supuesto, si puede distinguir entre las posibles excepciones que podrían lanzarse, no tiene que usar esto, pero si el código que reacciona 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.
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 declaración 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 a esta, pero no veo una respuesta clara a esa pregunta? aquí. Siento que https://.com/a/3996378/1503120 responde de manera excelente a esa pregunta. También he tratado de dilucidar los diversos significados de las distintas cláusulas en https://.com/a/22579805/1503120 .
Las instrucciones en el bloque else
se ejecutan si la ejecución cae fuera de la parte inferior del try
, si no hubo excepción. Sinceramente, nunca he encontrado una necesidad.
Sin embargo, manejo de notas 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 declaración try ... except.
Entonces, si tiene un método que podría, por ejemplo, lanzar un IOError
, y quiere atrapar las excepciones que genera, pero hay algo más que quiere hacer si la primera operación tiene éxito, y no quiere atrapar 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
, except
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
- la segunda operación solo se ejecuta si no hay excepción,
- se ejecuta antes del bloque
finally
, y - cualquier
IOError
s que plantea no está atrapado aquí
Me parece realmente ú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()
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.
Supongamos que su lógica de programació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()
Try-except-else es ideal para combinar el patrón EAFP con duck-typing :
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 la mitad y dejaba un archivo sin cerrar? Buena suerte depurando esa.
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).
Uno de los escenarios de uso que se me ocurren son las excepciones impredecibles, que se pueden eludir si lo intenta 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.