Lathack

Captura de errores y excepciones en Python

Captura de errores y excepciones en Python

Introducción

En otros lenguajes, como en C, se acostumbra a que las funciones retornen un valor específico cuando ocurre algún error. El código que llama a dicha función, chequea el valor de retorno y toma las medidas necesarias. En Python, cuando una función falla, en lugar de retornar un valor en particular lanza una excepción (vía la palabra reservada raise). El código que invocó a dicha función puede implementar un bloque para capturarla vía try y except. Las excepciones son un modelo para el manejo de errores. Python cuenta con soporte de primer nivel para las mismas.

¿Cómo implementamos la captura de errores y excepciones en Python?

Es posible hacer uso de las excepciones que incorpora el lenguaje. Algunas de ellas son: ValueError, TypeError, RuntimeError, KeyError (la convención de nombramiento difiere de las funciones y otros objetos, es decir, en las excepciones cada término se escribe con su primera letra en mayúscula y no se emplean guiones bajos).

Por ejemplo, int() sirve para convertir números de coma flotante y cadenas a su respectiva representación numérica.

int(«3»)

Out:

3

Cuando la cadena no puede ser convertida a entero, porque no es un número, lanza la excepción ValueError.

Captura de errores y excepciones en Python

Utilizando las palabras claves try y except podemos capturar la excepción (por ejemplo, el mensaje de error de la imagen anterior), evitando que se propague y se ejecute alguna otra acción. Por ejemplo:

try:

    int(«Hola mundo»)

except ValueError:

    print(«Eso no es un número.»)

Out:

Eso no es un número.

Es importante aclarar que, si una excepción se propaga sin que ningún bloque de código la capture, el programa finaliza inmediatamente sin concluir las líneas de código siguientes.

TypeError

Ahora bien, int() lanzará «TypeError» cuando se le pase como argumento un objeto que no pueda ser representado como un número, por ejemplo, una lista. Simplemente podemos agregar otra cláusula except para capturar dicha excepción.

try:

    int([1,2,3])

except ValueError:

    print(«Eso no es un número.»)

except TypeError:

    print(«Eso es una colección, no se puede convertir a entero»)

Out:

Eso es una colección, no se puede convertir a entero

Si queremos capturar ambas excepciones en un mismo bloque de código:

try:

    int([1,2,3])

except (ValueError, TypeError):

    print(«Tipo de dato incorrecto o no puede ser convertido»)

Out:

Tipo de dato incorrecto o no puede ser convertido

La cláusula try/except también acepta else, un bloque de código que es ejecutado cuando no se ha capturado ninguna de las excepciones de las contempladas.

try:

    int(«15»)

except Exception:

    print(«Ha ocurrido un error.»)

else:

    print(«Todo ha salido bien.»)

Out:

Todo salió bien

Finally

A los ya vistos bloques try, except y else podemos añadir dos bloque más, el «finally«. Dicho bloque se ejecuta siempre, haya o no haya habido excepción. Por ejemplo:

try:

    int(«10»)

except Exception:

    print(«Ocurrió un error.»)

else:

    print(«Todo salió bien.»)

finally:

    print(«Final del bloque»)

Out:

Todo salió bien

Final del bloque

Como se vé, si no sabemos qué excepción puede lanzarse, podemos usar la clase genérica Exception, la cual representa un «comodín» con respecto a su uso, ya que controla cualquier tipo de excepción. La mayoría de las excepciones heredan de esta, por ejemplo:

try:

    int(«Hola mundo»)

except Exception:

    print(«Ocurrió un error.»)

Out:

Ocurrió un error

Otras excepciones

Keyerror

Esta excepción es lanzada cuando se intenta acceder a una clave de un diccionario que no existe:

d = {«a»: 1}

d[«b»]

Out:

Traceback (most recent call last):

File «<stdin>», line 1, in <module>

KeyError: ‘b’

IndexError

Esta excepción es lanzada cuando se intenta acceder a un índice de una lista que no existe:

numeros=[10,20,30]

numeros[8]

Out:

Traceback (most recent call last):

File «<stdin>», line 1, in <module>

IndexError: list index out of range

ZeroDivisionError

La excepción «ZeroDivisionError» es lanzada cuando se intenta dividir por cero:

10 / 0

Out:

Traceback (most recent call last):

File «<stdin>», line 1, in <module>

ZeroDivisionError: division by zero

KeyboardInterrupt

Esta excepción es lanzada cuando cancelamos la operación del programa. Es decir, cuando presionamos Ctrl+c (usado para detener procesos):

Captura de errores y excepciones en Python

Veamos los tres tipos de respuesta que podemos tener:

Por último, podemos crear nuevas excepciones del siguiente modo, para luego utilizarla vía raise y except.

class NuevaExcepcion(Exception):

    pass

Esta sintaxis se entenderá mejor cuando veamos el funcionamiento del Paradigma de Objetos y cómo se aplica en este lenguaje.

Para tener en cuenta:

Debemos tener en cuenta que, al usar estas excepciones, no debemos generar una mala experiencia de usuario. Es decir, en el caso de retornar una excepción a casusa de un error, el programa NO debe dejar de ejecutarse o pararse por completo y reiniciarse. Para esto, hacemos uso de buenas prácticas como la función braek.

Veamos el siguiente script:

Captura de errores y excepciones en Python

Como podemos ver, siempre que el valor ingresado sea TRUE, el programa dejará de ejecutarse con efectividad. Ahora bien, en caso de ser FALSE (un dato que no sea int) retornará el mensaje de except. Cabe mencionar que la excepción finally se ejecutará por más que sea TRUE o FALSE.

Veamos el resultado que obtenemos:

Lanzar Excepciones

Ahora volvamos al ejemplo de nuestra rudimentaria función sumar(), que se veía así:

def sumar(a, b):

    return a + b

Como se trata de una operación aritmética, lo ideal sería poder chequear que los argumentos sean números enteros (int) o de coma flotante (float). Si bien dos colecciones del mismo tipo pueden concatenarse a través del operador +, no es la intención de nuestra función.

Utilizando la función incorporada isinstance() podemos chequear si un objeto es de un tipo de dato determinado.

Captura de errores y excepciones en Python

Como podemos ver, a través del isinstance(), especificamos que los argumentos a y b solo pueden ser del tipo int o float. Y, a través de raise, el tipo de error a retornar en caso de no cumplir las condiciones anteriores.

Veamos la respuesta:

Primero obtenemos las respuestas de los dos primeros print() y, para el caso del tercer print(), obtenemos la respuesta de error ya que, los datos no son correctos. Por lo tanto, con raise podemos lanzar excepciones de forma voluntaria. También, podemos observar que, con la funcionalidad raise, se detiene la ejecución, ya que, no se imprime el cuarto print(“Esto es un ejemplo”). Esto se debe a que las excepciones hacen que todo el programa se detenga donde se produjo dicha excepción.

El segundo argumento de isinstance() puede ser un tipo de dato o una tupla. Si es un tipo de dato, retorna True si el primer argumento efectivamente coincide con ese tipo de dato. Ahora bien, si es una tupla, retorna True si el primer argumento coincide con alguno de los tipos de datos contenidos en ella. Por convención, obtenemos TypeError cuando se quiere indicar que se obtuvo un argumento de un tipo inesperado, y ValueError cuando el tipo es correcto pero el valor no lo es.

Conclusión:

Con esto concluimos que la captura de errores y excepciones en Python es fundamental para el desarrollo de cualquier proyecto, ya que no solo obviamos los errores de salida y mejoramos la experiencia de usuario, sino que mejoramos la seguridad del mismo. Un mensaje de este tipo de error puede significar un dato muy importante para un cibercriminal.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

18 + 19 =

Lathack
Scroll al inicio