¿Cuál es la razón para que exista try-except-else?
Un trybloque le permite manejar un error esperado. El exceptbloque solo debe capturar excepciones que esté preparado para manejar. Si maneja un error inesperado, su código puede hacer lo incorrecto y ocultar errores.
Se elseejecutará una cláusula si no hubo errores, y al no ejecutar ese código en el trybloque, evitará detectar un error inesperado. Nuevamente, detectar 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, elsey finally. Entonces es en realidad try-except-else-finally.
elseevaluará solo si no hay excepción del trybloque. 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
así que si comparamos una elsecon 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, mantenible y con menos errores.
finally
finally se ejecutará sin importar qué, incluso si otra línea se está evaluando con una declaración de devolución.
Desglosado con pseudocódigo
Podría ser útil desglosar esto, en la forma más pequeña posible que muestre todas las características, con comentarios. Suponga que este pseudocódigo está 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 elsebloque en el trybloque en su lugar, donde se ejecutaría si no hubiera excepciones, pero ¿y si ese código genera una excepción del tipo que estamos atrapando? Dejarlo en el trybloque escondería ese error.
Queremos minimizar las líneas de código en el trybloque para evitar detectar excepciones que no esperábamos, bajo el principio de que si nuestro código falla, queremos que falle en voz alta. Esta es una mejor práctica .
Entiendo 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 Exceptionson errores, aunque Python usa algunos de ellos para cosas como finalizar forbucles ( 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ó:
Digamos que tiene un método que hace ping a una API externa y desea manejar la excepción en una clase fuera del contenedor API, ¿simplemente devuelve e del método bajo la cláusula except donde e es el objeto de excepción?
No, no devuelve la excepción, simplemente vuelva a subirla con un desnudo raisepara preservar el stacktrace.
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 la traza inversa con el encadenamiento de excepciones:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise DifferentException from the_exception
Elaboro mi respuesta aquí .