0%
Gestión de excepciones en Python

Excepciones

Anticipa y gestiona los errores en tus programas

10-15 min

Gestión de excepciones en Python

Las excepciones son eventos que se producen durante la ejecución de un programa y que alteran el flujo normal de instrucciones. En Python, las excepciones son objetos que representan errores. La gestión de excepciones es crucial para desarrollar aplicaciones robustas que puedan afrontar situaciones imprevistas sin fallar.

En este tutorial vamos a explorar cómo identificar, gestionar y crear excepciones en Python.

¿Por qué gestionar las excepciones?

La gestión de excepciones es importante por varias razones:

  1. Robustez: Un programa que gestiona correctamente las excepciones puede seguir funcionando incluso cuando se producen errores.
  2. Experiencia de usuario: Mostrar mensajes de error amigables en lugar de trazas de error técnicas.
  3. Depuración: Obtener información detallada sobre el error para facilitar su corrección.
  4. Gestión de recursos: Asegurarse de que los recursos (archivos, conexiones de red, etc.) se liberan correctamente, incluso en caso de error.

Tipos de excepciones habituales en Python

Python incluye numerosos tipos de excepciones integrados. Estos son algunos de los más habituales:

  • SyntaxError: Error en la sintaxis del código.
  • NameError: Intento de usar una variable no definida.
  • TypeError: Operación o función aplicada a un objeto de tipo inadecuado.
  • ValueError: Operación o función que recibe un argumento del tipo correcto pero con un valor inadecuado.
  • IndexError: Intento de acceder a un índice que no existe en una secuencia.
  • KeyError: Intento de acceder a una clave que no existe en un diccionario.
  • FileNotFoundError: Intento de abrir un archivo que no existe.
  • ZeroDivisionError: División por cero.
  • ImportError: Fallo al importar un módulo.
  • IOError: Error de entrada/salida (por ejemplo, al leer un archivo).
  • AttributeError: Intento de acceder a un atributo inexistente.

Estructura try-except-else-finally

Python utiliza los bloques try, except, else y finally para gestionar las excepciones.

Estructura básica try-except

try:
    # Código susceptible de generar una excepción
    resultat = 10 / 0
except ZeroDivisionError:
    # Código que se ejecuta si se produce una ZeroDivisionError
    print("Erreur : Division par zéro !")

En este ejemplo, cuando 10 / 0 genera una ZeroDivisionError, se ejecuta el bloque except correspondiente.

Capturar varios tipos de excepciones

Puedes capturar distintos tipos de excepciones con manejadores independientes:

try:
    # Código susceptible de generar excepciones
    nombre = int(input("Entrez un nombre : "))
    resultat = 10 / nombre
except ValueError:
    # Se ejecuta si la entrada no es un número válido
    print("Erreur : Veuillez entrer un nombre valide.")
except ZeroDivisionError:
    # Se ejecuta si nombre == 0
    print("Erreur : La division par zéro n'est pas autorisée.")

También puedes capturar varias excepciones con el mismo manejador:

try:
    # Código susceptible de generar excepciones
    nombre = int(input("Entrez un nombre : "))
    resultat = 10 / nombre
except (ValueError, ZeroDivisionError):
    # Se ejecuta si se produce alguna de las excepciones mencionadas
    print("Erreur : Entrée invalide ou division par zéro.")

Capturar todas las excepciones

Aunque por lo general no se recomienda (porque puede ocultar errores inesperados), es posible capturar todas las excepciones:

try:
    # Código susceptible de generar cualquier excepción
    # ...
except Exception as e:
    # Se ejecuta para cualquier excepción que herede de Exception
    print(f"Une erreur s'est produite : {e}")

Bloque else

El bloque else se ejecuta si no se lanza ninguna excepción en el bloque try:

try:
    nombre = int(input("Entrez un nombre : "))
    resultat = 10 / nombre
except ValueError:
    print("Entrée invalide.")
except ZeroDivisionError:
    print("Division par zéro.")
else:
    # Este bloque se ejecuta si no se lanza ninguna excepción
    print(f"Le résultat est {resultat}")

Bloque finally

El bloque finally se ejecuta pase lo que pase, se lance o no una excepción:

try:
    fichier = open("donnees.txt", "r")
    # Operaciones sobre el archivo
except FileNotFoundError:
    print("Le fichier n'existe pas.")
finally:
    # Este bloque se ejecuta siempre
    # Ideal para liberar recursos
    if 'fichier' in locals():
        fichier.close()
        print("Fichier fermé.")

El bloque finally es especialmente útil para asegurarse de que los recursos se liberan correctamente, incluso en caso de error.

Lanzar excepciones

Puedes lanzar (o “throw”) excepciones de forma deliberada mediante la instrucción raise:

def diviser(a, b):
    if b == 0:
        raise ZeroDivisionError("Division par zéro non autorisée")
    return a / b

try:
    resultat = diviser(10, 0)
except ZeroDivisionError as e:
    print(f"Erreur : {e}")

Crear excepciones personalizadas

Puedes crear tus propios tipos de excepciones heredando de la clase Exception o de una de sus subclases:

class ValeurNegativeError(Exception):
    """Excepción lanzada cuando se utiliza un valor negativo que no debería serlo."""
    pass

def calculer_racine_carree(nombre):
    if nombre < 0:
        raise ValeurNegativeError("La racine carrée d'un nombre négatif n'est pas définie pour les nombres réels.")
    import math
    return math.sqrt(nombre)

try:
    resultat = calculer_racine_carree(-1)
except ValeurNegativeError as e:
    print(f"Erreur : {e}")

Aserciones

Las aserciones son comprobaciones de depuración que verifican si una condición es verdadera. Si la condición es falsa, se lanza una excepción AssertionError:

def diviser(a, b):
    assert b != 0, "Le diviseur ne peut pas être zéro"
    return a / b

try:
    resultat = diviser(10, 0)
except AssertionError as e:
    print(f"Assertion échouée : {e}")

Las aserciones se utilizan principalmente para la depuración y las pruebas, y pueden desactivarse en modo de producción.

Con la instrucción with

La instrucción with se utiliza para garantizar que los recursos se gestionan correctamente, incluso en caso de excepción. Es una forma más limpia de gestionar las excepciones en operaciones que requieren recursos como los archivos:

try:
    with open("fichier.txt", "r") as fichier:
        contenu = fichier.read()
        # El archivo se cierra automáticamente al final del bloque with,
        # incluso si se lanza una excepción
except FileNotFoundError:
    print("Le fichier n'existe pas.")

Jerarquía de excepciones

Las excepciones en Python forman una jerarquía. Esta es una versión simplificada de dicha jerarquía:

  • BaseException
    • Exception
      • ArithmeticError
        • ZeroDivisionError
        • OverflowError
      • LookupError
        • IndexError
        • KeyError
      • OSError
        • FileNotFoundError
        • PermissionError
      • TypeError
      • ValueError
      • …
    • SystemExit
    • KeyboardInterrupt
    • …

Cuando capturas excepciones, el orden es importante. Si tienes varios bloques except, Python los comprueba en orden. Si una excepción es una subclase de otra que ya has capturado, nunca se llegará a ella:

try:
    # Código susceptible de generar excepciones
    # ...
except Exception:
    # Este bloque capturará todas las excepciones que heredan de Exception
    print("Une exception s'est produite")
except ZeroDivisionError:
    # Este bloque NUNCA se alcanzará porque ZeroDivisionError es una subclase de Exception
    print("Division par zéro")

Para evitar este problema, coloca las excepciones más específicas antes que las más generales.

Buenas prácticas en la gestión de excepciones

  1. Sé específico: Captura excepciones específicas en lugar de utilizar un except genérico.

  2. No suprimas los errores en silencio: Evita capturar una excepción sin gestionarla correctamente o sin dejar constancia de ella.

  3. Utiliza finally para la limpieza: Utiliza el bloque finally para asegurarte de que los recursos se liberan correctamente.

  4. Crea excepciones personalizadas cuando sea apropiado: Esto puede hacer que tu código sea más legible y permitir una gestión más precisa de los errores.

  5. Mantén los bloques try pequeños: Incluye en el bloque try únicamente el código susceptible de generar la excepción.

  6. Registra las excepciones en el log: En las aplicaciones de producción, conviene guardar las excepciones en archivos de log.

Conclusión

La gestión eficaz de las excepciones es una competencia esencial para cualquier programador de Python. Te permite escribir programas robustos que pueden gestionar los errores de forma elegante.

En este tutorial hemos explorado cómo identificar, capturar y lanzar excepciones, cómo crear tus propios tipos de excepciones y cómo utilizar la instrucción with para gestionar los recursos. También hemos comentado las buenas prácticas para una gestión eficaz de las excepciones.

En el próximo tutorial abordaremos la manipulación de archivos en Python, un ámbito en el que la gestión de excepciones es especialmente importante.

Comentarios

Los comentarios funcionan con GitHub Discussions

Inicia sesión con GitHub para participar en la discusión

¡Enlace copiado!