Python gestiona los errores de dos formas diferentes: por un lado tenemos los típicos Errores de Sintaxis y por otro las Excepciones. En esta pequeña guía explicaré cada uno de ellos.
Errores de Sintaxis
Los errores de sintaxis se producen cuando escribimos código y este no está bien escrito, por lo que Python nos devolverá un SyntaxError
o Error de Sintaxis.
Lo normal cuando obtenemos un error, es modificar nuestro código y de está forma evitamos que el programa se detenga. Pero esta no siempre es la forma más eficaz de hacerlo ya que podemos crear verificaciones condicionales para evitar que se produzcan errores.
1 2 |
#! /usr/bin/env python3 print("Hola') |
1 2 3 4 |
File "nuevo.py", line 3 print("Hola') ^ SyntaxError: EOL while scanning string literal |
Excepciones
Cuando escribimos código y este no se comporta como debe, Python también nos puede devolver Excepciones
. Entre las excepciones más comunes tenemos: TypeError, IndexError, ValueError o NameError.
Si necesitas consultar información detallada sobre todos los tipos de excepciones y cuando se producen cada uno de ellas, podéis seguir este enlace de la documentación oficial de Python.
1 2 |
with open("file.txt") as f: f.readline() |
1 2 3 4 |
Traceback (most recent call last): File "nuevo.py", line 17, in <module> with open("file.txt") as f: FileNotFoundError: [Errno 2] No such file or directory: 'file.txt' |
La construcción Try-Except
La construcción try-except
nos permite controlar las excepciones que puedan producirse en nuestro código. Continuando con el ejemplo anterior podemos incluir la función open() en un bloque try. De esta forma se intenta abrir el fichero y si no se consigue accedemos al bloque except, donde podemos gestionar el error que se ha producido.
1 2 3 4 5 6 7 8 9 10 11 12 |
#! /usr/bin/env python3 def leer_fichero(fichero): try: with open(fichero) as f: return f.readline() except FileNotFoundError: return "Fichero no encontrado." except OSError: return "Error I/O." except (ZeroDivisionError, ValueError, TypeError): return None |
Si retornamos None un bloque except, le estaremos diciendo que no continúe ejecutando el resto del código. Y recuerda que podemos incluir tantos bloques except como necesitemos.
Lanzar Errores Personalizados
En Python podemos lanzar excepciones cuando estás ocurran y para ello usaremos la palabra clave raise
. Supongamos la siguiente función que valida un nombre de usuario. Podemos lanzar un error personalizado cuando el nombre de usuario no contenga ningún carácter.
1 2 3 4 5 6 7 8 9 |
#!/usr/bin/env python3 def validar_usuario(usuario, longitud_minima): if len(usuario) < longitud_minima: raise ValueError("El usuario debe tener al menos 1 carácter.") return True usuario="" print(validar_usuario(usuario, 1)) |
Una alternativa a la palabra clave raise y que usaremos para evitar situaciones que nunca deberían suceder, es la palabra clave assert
. Assert intenta comprobar que una expresión condicional es verdadera y si es falsa genera un error con el mensaje que le indiquemos.
1 2 |
#! /usr/bin/env python3 assert type(usuario) == str, "El nombre de usuario debe ser una cadena." |
Los assert suelen ser muy útiles cuando depuramos códigos que no se comporta de la manera que esperamos. Podemos incluirlos en la parte del código donde algo que no debería estar sucediendo, está sucediendo.
Pruebas para Errores esperados (expected errors)
Cuando realizamos una Prueba Unitaria y queremos lanzar un error con raise, usaremos el método assertRaises(),
proporcionado por el módulo de prueba unittest. Veamos la función iva() de nuestro tutorial de Pruebas Unitarias con Python, cuando recibe parámetros que no tienen ningún sentido, como por ejemplo un valor negativo.
1 2 3 |
class TestIva(unittest.TestCase): def test_valor_negativo(self): self.assertRaises(ValueError, iva, -1) |
El método que hemos creado llama a la función que queremos probar usando un bloque try-except y comprueba que genera el error que esperamos. Por lo que vamos a necesitar modificar nuestra función iva() indicando el tipo de error ValueError, que se mostrará cuando el importe sea menor que 1.
1 2 3 4 5 6 7 8 9 10 |
def iva(importe): if importe == "": return 0 elif type(importe) == str: return 0 elif importe < 1: raise ValueError("el importe debe ser mayor que 0") else: result = round(float(importe)*0.21, 2) return result |