El manejo de excepciones con Python

El manejo de excepciones con Python

Hasta ahora, hemos visto de manera muy básica y sin entrar en detalle el manejo de excepciones en Python. Este tema vamos a necesitarlo para mejorar el proyecto de bases de datos que se está realizando en el curso, aunque te va a servir para hacer cualquier programa Python a partir de ahora.


¿Qué son las excepciones de Python y por qué son importantes?

Las excepciones de Python, son eventos producidos durante la ejecución de un programa. Estos eventos, si se producen y no se manejan, producirán una interrupción en dicho programa, hará que deje de ejecutarse.

Tipos de excepciones en Python

En Python, contamos con una gran cantidad de tipos de excepciones. Veamos brevemente, algunas de las más comunes:

Excepción NameError

La excepción NameError es producida, cuando se intenta acceder a una variable o a una función que no ha sido definida.

Para producir una excepción de tipo NameError, basta con llamar a una variable inexistente.

print(a)

Error en la consola

NameError: name 'a' is not defined.

El error dice: el nombre 'a' no está definido.

Excepción ValueError

La excepción ValueError es producida cuando se pasa un valor incorrecto a una función o a un método. Por ejemplo, si intentamos convertir una cadena de texto a entero usando la función "int()" y la cadena no representa un número entero válido.

print(int("¿Se puede pasar texto a int?"))

Error en la consola

ValueError: invalid literal for int() with base 10: '¿Se puede pasar texto a int?'

El error dice: literal inválido para int() con base 10.

Excepción IndexError

La excepción IndexError se produce cuando intentamos acceder a un índice fuera de rango de una lista, una tupla o un diccionario.

mi_lista = [1, 2, 3]
print(mi_lista[10])

Error en la consola

IndexError: list index out of range

El error dice: índice de lista fuera de rango.

Excepción TypeError

La excepción TypeError se produce cuando intentamos realizar una operación con objetos de tipos incompatibles. Por ejemplo, si intentamos sumar un entero y una cadena de texto.

print("Texto" + 10)

Error en la consola

TypeError: can only concatenate str (not "int") to str

El error dice: solo se puede concatenar str (no "int") a str.

Excepción KeyError

La excepción se produce cuando intentamos acceder a una clave que no existe en un diccionario.

diccionario = {"a": 1, "b": 2}
print(diccionario["c"])

Error en la consola

KeyError: 'c'

Excepción SyntaxError

La excepción SyntaxError es producida cuando el código contiene errores de sintaxis que impiden que el intérprete lo ejecute. Por ejemplo, si olvidamos poner dos puntos al final de una línea de código o si escribimos una palabra clave de forma incorrecta.


if variable

Error en la consola

SyntaxError: expected ':'

El error dice: se esperaba ':'.

Excepción ZeroDivisionError

La excepción ZeroDivisionError se produce cuando intentamos hacer una división por cero.

print(10 / 0)

Error en la consola

ZeroDivisionError: division by zero

El error dice: división por cero.

OSError: se produce cuando ocurre un error al acceder a un archivo o a una carpeta en el sistema operativo.

with open("archivo*cualquiera", "r") as archivo:
    pass

Error en la consola

OSError: [Errno 22] Invalid argument: 'archivo*cualquiera'

El error dice: error 22. Argumento inválido: 'archivo*cualquiera'.

El asterisco no es válido para nombre de archivo y se produce esta excepción.

Excepción IndentationError

La excepción IndentationError, es un error que suele ocurrir cuando empezamos a aprender Python o cuando copiamos código de alguna parte.

Sencillamente, aparece cuando ponemos los elementos en el código mal indentados o les falta un bloque de código indentado.

Un ejemplo, es este if:

variable = True

if variable:
print("El valor es True")

Error en la consola

IndentationError: expected an indented block after 'if' statement on line 3

Aquí, identifica el print() como código perteneciente a la hoja de Python y no como parte del if.

Los bloques try, except y finally de Python

Los bloques try, except y finally de Python nos sirven para realizar ciertas acciones en caso de que ocurran fallos o no.

Aquí tienes un ejemplo con el manejo en concreto de la excepción ZeroDivisionError.

Se intenta almacenar con el bloque try, el resultado de la división. Si no ocurre una excepción, se va a ejecutar primero este bloque. Por lo que se mostrará el resultado de la división en la consola.

Con el bloque except, estoy manejando solo un posible error de tipo "ZeroDivisionError". Este bloque se va a ejecutar solo si ocurre un error de este tipo.

El bloque finally, es un bloque que se ejecuta siempre, independientemente de cuál de los otros dos bloques se ejecute.


def dividir(dividendo, divisor):
    try:
        # Intentamos realizar la división
        resultado = round(dividendo / divisor, 2)
        print(resultado)
    except ZeroDivisionError:
    # En el caso de que se produzca una excepción ZeroDivisionError, mostramos un mensaje de error
        print("No se puede dividir por cero.")
    finally:
        # Mostramos un mensaje de finalización
        print("La operación de división ha finalizado.")
        
dividir(10,3)

Resultado en la consola

3.33
La operación de división ha finalizado.

En este caso, se ha ejecutado el bloque try y después, el finally.

dividir(10,0)

Resultado en la consola

No se puede dividir por cero.
La operación de división ha finalizado.

Esta vez, se ha ejecutado el bloque except y el finally.

¿Qué ocurre si pongo esto en la llamada?

dividir(10,"texto")

Error en la consola

TypeError: unsupported operand type(s) for /: 'int' and 'str'

Me da un TypeError (error de tipo de dato). Operando no soportado para "/": int y str.

Manejo de varias excepciones a la vez con Python

Normalmente, aunque es más trabajoso, conviene ir añadiendo bloques except para manejar los diferentes tipos de excepciones que van ocurriendo. Sin embargo, si tienes un programa complejo, normalmente, querrás tener diferentes soluciones en caso de que el usuario cometa diferentes excepciones. No se aprecia mucho con ejemplos tan simples como los dados hasta ahora, pero iré poniendo ejemplos durante el curso.

En esta ocasión, tengo el mismo programa de antes. Solo que en el except (línea 6), le he quitado el tipo de excepción. Esto maneja cualquier tipo de excepción.

def dividir(dividendo, divisor):
    try:
        # Intentamos realizar la división
        resultado = round(dividendo / divisor, 2)
        print(resultado)
    except:
    # En el caso de que se produzca una excepción ZeroDivisionError, mostramos un mensaje de error
        print("No se puede dividir por cero.")
    finally:
        # Mostramos un mensaje de finalización
        print("La operación de división ha finalizado.")
        
dividir(10,"texto")

Resultado en la consola

No se puede dividir por cero.
La operación de división ha finalizado.

En este caso, el código no finaliza con una excepción, pero el mensaje específico para el fallo de la división por cero, ya no me sirve de forma genérica, ahora tendría que cambiarlo y ser menos específico con algo como "Ocurrió un error."

Como puedes ver, es más práctico ir avisando al usuario de cada tipo de error, así sabe más fácilmente que está haciendo mal.

Imagina que tu sistema operativo, cada vez que ocurre un error del tipo que sea, te dijera "Ocurrió un error", pero no te dijera ni cuál, ni con qué.

Si quieres dar soluciones diferentes a cada tipo de excepción, puedes hacerlo así:

def dividir(dividendo, divisor):
    try:
        # Intentamos realizar la división
        resultado = round(dividendo / divisor, 2)
        print(resultado)
    except ZeroDivisionError:
    # En el caso de que se produzca una excepción ZeroDivisionError...
        print("No se puede dividir por cero.")
    except TypeError:
    # En el caso de que se produzca una excepción TypeError...
        print("Has escrito un valor incorrecto para la división. Pon un número.")
    finally:
        # Mostramos un mensaje de finalización
        print("La operación de división ha finalizado.")

Si provocamos un error de tipo…


dividir(10,"texto")

Resultado en la consola

Has escrito un valor incorrecto para la división. Pon un número.
La operación de división ha finalizado.

Y si el error es de división por cero…

dividir(10,0)

Resultado en la consola

No se puede dividir por cero.
La operación de división ha finalizado.

Valores booleanos como números en Python

Una curiosidad ¿Sabías que se pueden utilizar valores booleanos como un 1 (True) y un 0 (False)?

En el ejemplo anterior, si dividimos por un True, en realidad lo hacemos con un 1.

dividir(10,True)

En este caso, no hay error de tipo de dato y nos da una salida del bloque try, puesto que es como pasarle un 10 y un 1 de argumentos.

Resultado en la consola

10.0
La operación de división ha finalizado.

Bien, en cambio, puesto que False es un 0, se ejecuta el bloque except ZeroDivisionError:

dividir(10,False)

Resultado en la consola

No se puede dividir por cero.
La operación de división ha finalizado.

Aquí tienes el temario completo de todo el curso de Máster en Python.


2 comentarios en «0»

Deja una respuesta

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

numpy matplotlib Entrada anterior Visualizando vectores en 3D con Python, NumPy y Matplotlib
curso Java Entrada siguiente El constructor new en Java: una guía para principiantes