Excepciones
Los errores de ejecución son llamados comúnmente excepciones y por eso de ahora en más utilizaremos ese nombre. Durante la ejecución de un programa, si dentro de una función surge una excepción y la función no la maneja, la excepción se propaga hacia la función que la invocó, si esta otra tampoco la maneja, la excepción continua propagándose hasta llegar a la función inicial del programa y si esta tampoco la maneja se interrumpe la ejecución del programa. Veamos entonces como manejar excepciones.
Para el manejo de excepciones los lenguajes proveen ciertas palabras reservadas, que nos permiten manejar las excepciones que puedan surgir y tomar acciones de recuperación para evitar la interrupción del programa o, al menos, para realizar algunas acciones adicionales antes de interrumpir el programa.
En el caso de Python, el manejo de excepciones se hace mediante los bloques que utilizan las sentencias try, except y finally.
Dentro del bloque try se ubica todo el código que pueda llegar a levantar una excepción , se utiliza el término levantar para referirse a la acción de generar una excepción.
A continuación se ubica el bloque except, que se encarga de capturar la excepción y nos da la oportunidad de procesarla mostrando por ejemplo un mensaje adecuado al usuario . Veamos qué sucede si se quiere realizar una división por cero:
>>> dividendo = 5>>> divisor = 0>>> dividendo / divisor
Traceback (most recent call last):
File "<stdin>", line 1, in <module>ZeroDivisionError: integer division or modulo by zero
En este caso, se levantó la excepción ZeroDivisionError cuando se quiso hacer la división. Para evitar que se levante la excepción y se detenga la ejecución del programa, se utiliza el bloque try-except.
>>> try:
... cociente = dividendo / divisor
... except:
... print"No se permite la división por cero"
No se permite la división por cero
Dado que dentro de un mismo bloque try pueden producirse excepciones de distinto tipo, es posible utilizar varios bloques except, cada uno para capturar un tipo distinto de excepción.
Esto se hace especificando a continuación de la sentencia except el nombre de la excepción que se pretende capturar. Un mismo bloque except puede atrapar varios tipos de excepciones, lo cual se hace especificando los nombres de la excepciones separados por comas a continuación de la palabra except. Es importante destacar que si bien luego de un bloque try puede haber varios bloques except, se ejecutará, a lo sumo, uno de ellos.
try:
# aquí ponemos el código que puede lanzar excepciones
except IOError:
# entrará aquí en caso quese haya producido
# una excepción IOError
except ZeroDivisionError:
# entrará aquí en caso quese haya producido
# una excepción ZeroDivisionError
except:
# entrará aquí en caso quese haya producido
# una excepciónqueno corresponda a ninguno
# de los tipos especificados en los except previos
Como se muestra en el ejemplo precedente también es posible utilizar una sentencia except sin especificar el tipo de excepción a capturar, en cuyo caso se captura cualquier excepción, sin importar su tipo. Cabe destacar, también, que en caso de utilizar una sentencia except sin especificar el tipo, la misma debe ser siempre la última de las sentencias except, es decir que el siguiente fragmento de código es incorrecto
try:
# aquí ponemos el código que puede lanzar excepciones
except:
# ERRORde sintaxis, esta sentencia no puede estar aquí,
# sino que debería estar luego del except IOError.
except IOError:
# Manejo dela excepciónde entrada/salida
Finalmente, puede ubicarse un bloque finally donde se escriben las sentencias de finalización, que son típicamente acciones de limpieza. La particularidad del bloque finally es que se ejecuta siempre, haya surgido una excepción o no. Si hay un bloque except, no es necesario que esté presente el finally, y es posible tener un bloque try sólo con finally, sin except.
Veamos ahora como es que actúa Python al encontrarse con estos bloques. Python comienza a ejecutar las instrucciones que se encuentran dentro de un bloque try normalmente. Si durante la ejecución de esas instrucciones se levanta una excepción, Python interrumpe la ejecución en el punto exacto en que surgió la excepción y pasa a la ejecución del bloque except correspondiente.
Para ello, Python verifica uno a uno los bloques except y si encuentra alguno cuyo tipo haga referencia al tipo de excepción levantada, comienza a ejecutarlo. Sino encuentra ningún bloque del tipo correspondiente pero hay un bloque except sin tipo, lo ejecuta. Al terminar de ejecutar el bloque correspondiente, se pasa a la ejecución del bloque finally, si se encuentra definido.
Si, por otra parte, no hay problemas durante la ejecución del bloque try, se completa la ejecución del bloque, y luego se pasa directamente a la ejecución del bloque finally (si es que está definido).
Bajemos todo esto a un ejemplo concreto, supongamos que nuestro programa tiene que procesar cierta información ingresada por el usuario y guardarla en un archivo. Dado que el acceso a archivos puede levantar excepciones, siempre deberíamos colocar el código de manipulación de archivos dentro de un bloque try. Luego deberíamos colocar un bloque except que atrape una excepción del tipo IOError, que es el tipo de excepciones que lanzan la funciones de manipulación de archivos. Adicionalmente podríamos agregar un bloque except sin tipo por si surge alguna otra excepción. Finalmente deberíamos agregar un bloque finally para cerrar el archivo, haya surgido o no una excepción.
try:
archivo = open("miarchivo.txt")
# procesar el archivoexcept IOError:
print"Error de entrada/salida."# realizar procesamiento adicionalexcept:
# procesar la excepciónfinally:
# si el archivo no está cerrado hay que cerrarloifnot(archivo.closed):
archivo.close()
Algunas Excepciones Comunes
NameError: Esta excepción es levantada cuando el programa no puede encontrar un nombre local o global. El nombre que podría no ser encontrado está incluido en el mensaje de error.
TypeError: Esta excepción es levantada cuando una función se le pasa un objeto del tipo inapropiado como su argumento. Más detalles sobre el tipo incorrecto son proporcionados en el mensaje de error.
ValueError: Esta excepción ocurre cuando un argumento de función tiene el tipo correcto pero un valor inapropiado.
NotImplementedError: Esta excepción es levantada cuando se supone que un objeto apoye una operación pero no ha sido implementado aún. No deberías usar este error cuando la función dada no deba apoyar al tipo de argumento de entrada. En esas situaciones, levantar una excepción TypeError es más apropiado.
ZeroDivisionError: Esta excepción es levantada cuando proporcionas el segundo argumento para una operación de división o módulo como cero.
FileNotFoundError: Esta excepción es levantada cuando el archivo o diccionario que el programa solicitó no existe.
Manejar excepciones apropiadamente puede ser muy útil en situaciones en donde no es viable salir de un programa después de que este reciba una entrada inesperada. Espero que les haya sido útil 😃