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.
el enlace a youtube se te ha desconfigurado, puedes borrar este comentario después de arreglarlo 😉
Hola, gracias por avisar. Me sale correcto el vídeo en esta página. ¿Sigues sin verlo?