Cómo comprobar si se ha capturado una excepción en Python

PythonPythonBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio (lab), aprenderás cómo comprobar si se ha capturado una excepción en Python utilizando diferentes técnicas. El laboratorio se centra en el manejo de excepciones, un aspecto crucial para escribir código Python robusto y confiable.

El laboratorio te guiará a través de la comprensión del flujo de manejo de excepciones utilizando bloques try...except para manejar de forma elegante errores como ZeroDivisionError. Aprenderás cómo establecer una bandera (flag) dentro del bloque except para indicar que se ha capturado una excepción. Finalmente, el laboratorio presentará el concepto de utilizar gestores de contexto (context managers) para un manejo de excepciones más controlado.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/ErrorandExceptionHandlingGroup(["Error and Exception Handling"]) python(("Python")) -.-> python/FileHandlingGroup(["File Handling"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/ControlFlowGroup -.-> python/conditional_statements("Conditional Statements") python/ErrorandExceptionHandlingGroup -.-> python/catching_exceptions("Catching Exceptions") python/ErrorandExceptionHandlingGroup -.-> python/raising_exceptions("Raising Exceptions") python/FileHandlingGroup -.-> python/file_opening_closing("Opening and Closing Files") python/FileHandlingGroup -.-> python/file_operations("File Operations") python/AdvancedTopicsGroup -.-> python/context_managers("Context Managers") subgraph Lab Skills python/conditional_statements -.-> lab-559610{{"Cómo comprobar si se ha capturado una excepción en Python"}} python/catching_exceptions -.-> lab-559610{{"Cómo comprobar si se ha capturado una excepción en Python"}} python/raising_exceptions -.-> lab-559610{{"Cómo comprobar si se ha capturado una excepción en Python"}} python/file_opening_closing -.-> lab-559610{{"Cómo comprobar si se ha capturado una excepción en Python"}} python/file_operations -.-> lab-559610{{"Cómo comprobar si se ha capturado una excepción en Python"}} python/context_managers -.-> lab-559610{{"Cómo comprobar si se ha capturado una excepción en Python"}} end

Aprender el flujo de manejo de excepciones

En este paso, aprenderás sobre el manejo de excepciones en Python. El manejo de excepciones es una parte crucial para escribir código robusto y confiable. Te permite manejar de forma elegante los errores que pueden ocurrir durante la ejecución de tu programa, evitando que se bloquee y brindando una experiencia más amigable para el usuario.

Comencemos con un ejemplo sencillo. Imagina que quieres dividir dos números, pero el segundo número podría ser cero. Dividir por cero es una operación indefinida y generará un ZeroDivisionError en Python.

  1. Abre el editor de VS Code en el entorno de LabEx.

  2. Crea un nuevo archivo llamado division.py en el directorio ~/project.

    touch ~/project/division.py
  3. Edita el archivo division.py y agrega el siguiente código:

    ## division.py
    numerator = 10
    denominator = 0
    
    result = numerator / denominator
    
    print(result)
  4. Ejecuta el script utilizando el comando python:

    python ~/project/division.py

Verás un mensaje de error similar a este:

Traceback (most recent call last):
  File "/home/labex/project/division.py", line 4, in <module>
    result = numerator / denominator
ZeroDivisionError: division by zero

Este mensaje de error indica que se produjo un ZeroDivisionError porque intentamos dividir por cero. Sin manejo de excepciones, el programa se detiene abruptamente.

Ahora, usemos el manejo de excepciones para manejar este error de forma elegante.

  1. Modifica el archivo division.py para incluir un bloque try...except:

    ## division.py
    numerator = 10
    denominator = 0
    
    try:
        result = numerator / denominator
        print(result)
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")

    En este código, el bloque try contiene el código que podría generar una excepción. Si se produce un ZeroDivisionError dentro del bloque try, se ejecutará el código en el bloque except.

  2. Vuelve a ejecutar el script:

    python ~/project/division.py

Ahora, en lugar de bloquearse, el programa mostrará:

Error: Cannot divide by zero.

Esto demuestra la estructura básica del manejo de excepciones:

  • El bloque try encierra el código que podría generar una excepción.
  • El bloque except especifica el tipo de excepción a capturar y el código a ejecutar si se produce esa excepción.

También puedes capturar múltiples tipos de excepciones utilizando múltiples bloques except:

## division.py
numerator = 10
denominator = "abc"

try:
    result = numerator / int(denominator)
    print(result)
except ZeroDivisionError:
    print("Error: Cannot divide by zero.")
except ValueError:
    print("Error: Invalid input. Please enter a number.")

En este ejemplo, hemos agregado un controlador de excepción ValueError. Si el denominator no se puede convertir a un entero (por ejemplo, si es una cadena como "abc"), se generará un ValueError y se ejecutará el bloque except correspondiente.

Ejecuta el script:

python ~/project/division.py

Salida:

Error: Invalid input. Please enter a number.

El manejo de excepciones te permite escribir programas más robustos y amigables para el usuario al anticipar y manejar posibles errores.

Establecer una bandera (flag) en el bloque except

En este paso, aprenderás cómo utilizar una bandera (flag) dentro de un bloque except para controlar el flujo de tu programa en función de si se produjo una excepción o no. Esta es una técnica útil cuando necesitas realizar diferentes acciones dependiendo del resultado del bloque try.

Basándonos en el ejemplo anterior, supongamos que quieres calcular el inverso de un número, pero solo si la división fue exitosa. Puedes utilizar una bandera para indicar si la división fue exitosa y luego calcular el inverso en consecuencia.

  1. Abre el editor de VS Code en el entorno de LabEx.

  2. Modifica el archivo division.py en el directorio ~/project para incluir una bandera:

    ## division.py
    numerator = 10
    denominator = 2
    success = True  ## Inicializa la bandera en True
    
    try:
        result = numerator / denominator
        print("Result of division:", result)
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
        success = False  ## Establece la bandera en False si se produce un error
    except ValueError:
        print("Error: Invalid input. Please enter a number.")
        success = False ## Establece la bandera en False si se produce un error
    else:
        print("No exception occurred.")
    
    if success:
        try:
            reciprocal = 1 / result
            print("Reciprocal:", reciprocal)
        except ZeroDivisionError:
            print("Cannot calculate reciprocal of zero.")
    else:
        print("Reciprocal calculation skipped due to error.")

    En este código:

    • Inicializamos una bandera llamada success en True antes del bloque try.
    • Si se produce un ZeroDivisionError o ValueError, establecemos la bandera success en False dentro del bloque except correspondiente.
    • Después del bloque try...except, verificamos el valor de la bandera success. Si sigue siendo True, significa que no se produjo ninguna excepción y podemos calcular el inverso de forma segura. De lo contrario, omitimos el cálculo del inverso.
    • También agregamos un bloque else, que se ejecutará si no se produce ninguna excepción en el bloque try.
  3. Ejecuta el script con un denominador válido:

    python ~/project/division.py

    Salida:

    Result of division: 5.0
    No exception occurred.
    Reciprocal: 0.2
  4. Ahora, cambia el denominator a 0 y ejecuta el script nuevamente:

    ## division.py
    numerator = 10
    denominator = 0 ## Cambia el denominador a 0
    success = True
    
    try:
        result = numerator / denominator
        print("Result of division:", result)
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
        success = False
    except ValueError:
        print("Error: Invalid input. Please enter a number.")
        success = False
    else:
        print("No exception occurred.")
    
    if success:
        try:
            reciprocal = 1 / result
            print("Reciprocal:", reciprocal)
        except ZeroDivisionError:
            print("Cannot calculate reciprocal of zero.")
    else:
        print("Reciprocal calculation skipped due to error.")

    Ejecuta el script:

    python ~/project/division.py

    Salida:

    Error: Cannot divide by zero.
    Reciprocal calculation skipped due to error.

Esto demuestra cómo puedes utilizar una bandera en el bloque except para controlar el flujo de tu programa y realizar diferentes acciones en función de si se produjo una excepción o no.

Utilizar gestores de contexto (context managers) para el control

En este paso, aprenderás cómo utilizar gestores de contexto (context managers) en Python para simplificar el manejo de excepciones y garantizar que los recursos se gestionen adecuadamente, incluso si se producen excepciones. Los gestores de contexto son especialmente útiles cuando se trabaja con archivos, conexiones de red y otros recursos que deben cerrarse o liberarse explícitamente.

Un gestor de contexto es un objeto que define los métodos __enter__ y __exit__. La declaración with se utiliza para ejecutar un bloque de código dentro del contexto de un gestor de contexto. El método __enter__ se llama cuando se ingresa al bloque with, y el método __exit__ se llama cuando se sale del bloque with, independientemente de si se produjo una excepción.

Comencemos con un ejemplo sencillo de lectura de un archivo utilizando un gestor de contexto.

  1. Abre el editor de VS Code en el entorno de LabEx.

  2. Crea un nuevo archivo llamado file_handling.py en el directorio ~/project.

    touch ~/project/file_handling.py
  3. Edita el archivo file_handling.py y agrega el siguiente código:

    ## file_handling.py
    
    filename = "my_file.txt"
    
    try:
        with open(filename, "w") as f:
            f.write("Hello, LabEx!\n")
            f.write("This is a test file.\n")
    except IOError as e:
        print(f"An I/O error occurred: {e}")
    
    try:
        with open(filename, "r") as f:
            content = f.read()
            print("File content:")
            print(content)
    except FileNotFoundError:
        print(f"The file '{filename}' was not found.")
    except IOError as e:
        print(f"An I/O error occurred: {e}")

    En este código:

    • Utilizamos la declaración with open(filename, "w") as f: para abrir el archivo my_file.txt en modo de escritura ("w"). La función open() devuelve un objeto de archivo, que se asigna a la variable f.
    • La declaración with garantiza que el archivo se cierre automáticamente cuando se sale del bloque, incluso si se produce una excepción.
    • Escribimos dos líneas de texto en el archivo utilizando el método f.write().
    • Luego utilizamos la declaración with open(filename, "r") as f: para abrir el mismo archivo en modo de lectura ("r").
    • Leemos todo el contenido del archivo utilizando el método f.read() y lo imprimimos en la consola.
    • Encerramos las operaciones de archivo en bloques try...except para manejar posibles excepciones FileNotFoundError y IOError.
  4. Ejecuta el script:

    python ~/project/file_handling.py

    Salida:

    File content:
    Hello, LabEx!
    This is a test file.

    Si el archivo my_file.txt no existe, el script lo creará y escribirá el contenido especificado. Si el archivo ya existe, su contenido se sobrescribirá. La declaración with garantiza que el archivo se cierre adecuadamente en cualquier caso.

Consideremos otro ejemplo en el que podría ocurrir una excepción durante el procesamiento del archivo:

## file_handling.py
filename = "my_file.txt"

try:
    with open(filename, "r") as f:
        for line in f:
            ## Simulate an error during processing
            if "test" in line:
                raise ValueError("Simulated error during processing")
            print("Line:", line.strip())
except FileNotFoundError:
    print(f"The file '{filename}' was not found.")
except ValueError as e:
    print(f"A value error occurred: {e}")
except IOError as e:
    print(f"An I/O error occurred: {e}")

En este ejemplo, simulamos un error al generar una excepción ValueError si la línea contiene la palabra "test". Incluso si se produce este error, la declaración with garantiza que el archivo se cierre adecuadamente.

Ejecuta el script:

python ~/project/file_handling.py

Salida:

Line: Hello, LabEx!
A value error occurred: Simulated error during processing

Los gestores de contexto proporcionan una forma limpia y confiable de gestionar recursos y manejar excepciones en Python. Garantizan que los recursos se liberen adecuadamente, incluso si se producen errores, lo que hace que tu código sea más robusto y fácil de mantener.

Resumen

En este laboratorio, comenzaste aprendiendo sobre el manejo de excepciones en Python, una técnica crucial para escribir código robusto. Comenzaste con un ejemplo sencillo de división que genera una excepción ZeroDivisionError cuando se divide por cero, lo que hace que el programa se detenga. Luego, implementaste un bloque try...except para manejar adecuadamente la excepción ZeroDivisionError, evitando que el programa se bloquee y mostrando en su lugar un mensaje de error informativo.