Aprende a construir programas robustos que pueden anticipar y gestionar errores elegantemente con try-except.
Mientras programas, incluso con mucho cuidado, a veces ocurren errores. Estos errores, detectados por Python durante la ejecución del programa, se llaman excepciones. Una excepción es un evento que interrumpe el flujo normal de las instrucciones de tu código.
Si una excepción ocurre y no la "manejas" (o "capturas"), tu programa se detendrá abruptamente y mostrará un mensaje de error (traceback), lo cual no es una buena experiencia para el usuario ni para ti como desarrollador.
Piensa en esto: En un experimento de física, si un sensor falla y devuelve un dato no numérico, ¿preferirías que tu programa de análisis se cierre de golpe o que te avise del problema y continúe con los datos válidos (o pida una nueva entrada)? ¡El manejo de excepciones te permite lo segundo!
try y except: ¡Intentar y Capturar!
La forma fundamental de manejar excepciones en Python es con un bloque try-except. La idea es: "Intenta (try) ejecutar este código. Si ocurre un error específico (una excepción), en lugar de detenerte, ejecuta este otro código (except)". [cite: 34895]
try:
# Código que podría generar una excepción
# Por ejemplo, una división por cero, una conversión de tipo inválida, etc.
resultado = 10 / 0
print(f"El resultado es: {resultado}") # Esta línea no se ejecutará si hay error arriba
except ZeroDivisionError: # Se especifica el tipo de error que queremos capturar
# Código que se ejecuta SI ocurre una ZeroDivisionError en el bloque try
print("Error: ¡No puedes dividir por cero! 🚫")
# El programa continúa aquí después de manejar la excepción (o si no hubo excepción)
print("Fin del programa.")
La estructura try-except actúa como una red de seguridad: el bloque try es donde realizas la acción que podría fallar, y el bloque except es lo que haces si falla, evitando que el programa entero se rompa.
Cómo funciona:
try.except se omite y la ejecución continúa después de toda la estructura.try que coincide con el tipo especificado en except (ej. ZeroDivisionError), Python salta el resto del código en try y ejecuta el código dentro de except.except (o si no hubo error en try), el programa sigue con el código posterior.
Aunque podrías usar un except: genérico para atrapar cualquier error, ¡no es una buena práctica! Es mucho mejor ser específico sobre los tipos de excepciones que esperas y manejas. Esto hace tu código más predecible y fácil de depurar.
Python tiene muchos tipos de excepciones incorporadas. Algunas comunes que podrías encontrar en contextos científicos y matemáticos son:
ValueError: Se produce cuando una función recibe un argumento con un valor apropiado en tipo, pero incorrecto en contenido (ej. int("hola"), math.sqrt(-1)). [cite: 34915]TypeError: Ocurre cuando una operación o función se aplica a un objeto de un tipo inapropiado (ej. "2" + 3). [cite: 34914]ZeroDivisionError: Al intentar dividir entre cero. [cite: 34913]IndexError: Al intentar acceder a un índice de secuencia (lista, tupla) que está fuera de rango. [cite: 34916]KeyError: Al intentar acceder a una clave en un diccionario que no existe. [cite: 34917]FileNotFoundError: Cuando intentas abrir un archivo que no se encuentra. [cite: 34918]OverflowError: Cuando el resultado de una operación aritmética es demasiado grande para ser representado.try:
# Código propenso a errores
valor_str = input("Ingresa un número para calcular su inverso: ")
numero = float(valor_str)
inverso = 1 / numero
print(f"El inverso de {numero} es {inverso:.4f}")
except ValueError:
print("Error: Debes ingresar un valor numérico válido. 🔢")
except ZeroDivisionError:
print("Error: No se puede calcular el inverso de cero. ♾️")
except Exception as e: # Un capturador más genérico al final (opcional)
print(f"Ocurrió un error inesperado: {e}")
También puedes capturar múltiples excepciones en una sola cláusula except usando una tupla:
try:
x = int(input("Dame un número: "))
resultado = 100 / x
except (ValueError, ZeroDivisionError) as error_comun:
print(f"¡Ups! Algo salió mal con el número: {error_comun}")
Orden Importa: Si usas múltiples bloques except, Python los prueba en orden. Coloca los más específicos primero y los más genéricos (como except Exception:) al final. Si un except más genérico está antes, podría capturar un error que querías manejar de forma más específica.
else y finallyelse: Código si Todo Va Bien
Puedes añadir una cláusula else después de todos los except. El bloque de código dentro de else se ejecuta solo si el bloque try se completó sin generar ninguna excepción.
numerador = float(input("Numerador: "))
denominador = float(input("Denominador: "))
try:
resultado_division = numerador / denominador
except ZeroDivisionError:
print("Error: El denominador no puede ser cero. 🚫")
else:
# Esto solo se ejecuta si no hubo ZeroDivisionError
print(f"La división es {resultado_division:.3f} ✅")
print("Cálculo terminado.")
Es útil para separar el código que podría fallar (en try) del código que solo debe ejecutarse si el primero tuvo éxito (en else).
finally: Limpieza Garantizada
El bloque finally es especial: su código se ejecuta siempre, sin importar si ocurrió una excepción en el bloque try o no, e incluso si un except o else se ejecutó, o si hay un return, break o continue dentro del try.
Es ideal para tareas de "limpieza" que deben realizarse sí o sí, como cerrar un archivo, liberar una conexión de red, o apagar un dispositivo en un experimento físico.
# Simulando la apertura y cierre de un archivo de datos de experimento
archivo_datos = "datos_temp.txt"
try:
print(f"Intentando abrir el archivo '{archivo_datos}'... 📂")
# Simular lectura o escritura (podría fallar si el archivo no existe o no hay permisos)
# f = open(archivo_datos, "r")
# contenido = f.read()
# print(f"Contenido: {contenido[:30]}...") # Solo primeros 30 chars
# raise IOError("Error simulado durante la lectura del archivo!") # Para probar el except
print("Procesamiento del archivo completado exitosamente. ✅")
except FileNotFoundError:
print(f"Error: El archivo '{archivo_datos}' no fue encontrado. 😥")
except IOError as e:
print(f"Error de E/S al trabajar con el archivo: {e} 💔")
else:
print("No ocurrieron errores durante el manejo del archivo. 👍")
finally:
# Este bloque se ejecuta siempre, ideal para cerrar el archivo
# if 'f' in locals() and not f.closed: # Verificar si f existe y no está cerrado
# f.close()
print("Bloque 'finally': Operaciones de limpieza completadas (ej. archivo cerrado). 🧹")
as e)
Cuando capturas una excepción, a menudo quieres saber más sobre qué salió mal. Puedes asignar el objeto de la excepción a una variable usando as nombre_variable en la cláusula except.
try:
resultado = 10 / int("cero")
except ValueError as error_conversion:
print(f"¡Ocurrió un error de conversión! Detalles: {error_conversion}")
# error_conversion contendrá algo como: invalid literal for int() with base 10: 'cero'
except Exception as error_general: # Captura cualquier otra excepción
print(f"Error general: {error_general}")
raise)
A veces, quieres que tu propio código genere (o "lance") una excepción si detecta una condición de error que no puede manejar o que indica un uso incorrecto de una función. Para esto se usa la palabra clave raise. [cite: 34921]
# Función para calcular la velocidad angular (Física)
import math
def calcular_velocidad_angular(frecuencia_hz):
if not isinstance(frecuencia_hz, (int, float)):
raise TypeError("La frecuencia debe ser un número (Hz).")
if frecuencia_hz < 0:
raise ValueError("La frecuencia no puede ser negativa.")
return 2 * math.pi * frecuencia_hz
try:
omega1 = calcular_velocidad_angular(50) # Hz
print(f"Velocidad angular para 50 Hz: {omega1:.2f} rad/s")
omega2 = calcular_velocidad_angular(-10) # Esto lanzará ValueError
print(omega2) # No se ejecutará
except (ValueError, TypeError) as e:
print(f"Error al calcular velocidad angular: {e} 🛑")
Usar raise es útil para validaciones de entrada en tus funciones y para señalar condiciones de error específicas de tu lógica de programa.
Veamos cómo aplicar try-except en escenarios más concretos de matemáticas y física.
Evitar errores al calcular la raíz cuadrada de números negativos.
import math
def raiz_cuadrada_segura(numero_str):
try:
numero = float(numero_str)
if numero < 0:
raise ValueError("No se puede calcular la raíz de un número negativo con math.sqrt.")
resultado = math.sqrt(numero)
return f"La raíz cuadrada de {numero} es {resultado:.4f}"
except ValueError as e:
return f"Error: {e}"
print(raiz_cuadrada_segura("25"))
print(raiz_cuadrada_segura("-9"))
print(raiz_cuadrada_segura("texto"))
Manejar entradas incorrectas al pedir coordenadas.
import math
def calcular_distancia_puntos():
try:
x1 = float(input("Ingrese x1: "))
y1 = float(input("Ingrese y1: "))
x2 = float(input("Ingrese x2: "))
y2 = float(input("Ingrese y2: "))
distancia = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
return f"La distancia entre ({x1},{y1}) y ({x2},{y2}) es {distancia:.2f}"
except ValueError:
return "Error: Todas las coordenadas deben ser números."
except Exception as e:
return f"Ocurrió un error inesperado: {e}"
# print(calcular_distancia_puntos()) # Descomenta para probar
Evitar división por cero si el tiempo es cero.
def calcular_velocidad_mru():
try:
distancia_m = float(input("Distancia recorrida (metros): "))
tiempo_s = float(input("Tiempo transcurrido (segundos): "))
if tiempo_s == 0:
raise ZeroDivisionError("El tiempo no puede ser cero para calcular velocidad.")
velocidad = distancia_m / tiempo_s
return f"Velocidad: {velocidad:.2f} m/s"
except ValueError:
return "Error: Distancia y tiempo deben ser números."
except ZeroDivisionError as e:
return f"Error de cálculo: {e}"
finally:
print("--- Cálculo de velocidad finalizado ---")
# print(calcular_velocidad_mru()) # Descomenta para probar
Manejar la entrada del usuario para la unidad y el valor.
def convertir_temperatura():
try:
temp_str = input("Ingrese la temperatura (ej: 25C, 77F): ")
valor = float(temp_str[:-1]) # Toma todos menos el último caracter
unidad = temp_str[-1:].upper() # Toma el último caracter y lo pone en mayúscula
if unidad == 'C':
convertida = (valor * 9/5) + 32
return f"{valor}°C son {convertida:.1f}°F"
elif unidad == 'F':
convertida = (valor - 32) * 5/9
return f"{valor}°F son {convertida:.1f}°C"
else:
raise ValueError("Unidad no reconocida. Use 'C' o 'F'.")
except ValueError as e:
return f"Error de entrada: {e}"
except IndexError:
return "Error: Formato de entrada incorrecto (ej: 25C)."
# print(convertir_temperatura()) # Descomenta para probar
¡Excelente trabajo! Has aprendido a manejar las excepciones en Python, una habilidad esencial para cualquier programador. Ahora puedes escribir código que no solo funciona cuando todo va bien, sino que también puede anticipar, gestionar y recuperarse de errores de manera elegante.
Recuerda los bloques clave:
try: Para el código que podría fallar.except TipoDeError (as e): Para manejar errores específicos y opcionalmente obtener información sobre ellos.else: Para código que se ejecuta solo si no hubo errores en el try.finally: Para código de limpieza que se ejecuta siempre.raise: Para lanzar tus propias excepciones cuando sea necesario.Aplicar un buen manejo de excepciones hará tus programas más robustos, fáciles de usar y mucho más profesionales, especialmente en el ámbito científico donde la integridad de los datos y la estabilidad de los cálculos son cruciales.
¡Sigue Practicando! Experimenta en Google Colab. Intenta provocar diferentes tipos de errores en tus propios programas (división por cero, conversión de tipos incorrecta, acceso a archivos inexistentes) y luego implementa bloques try-except para manejarlos. ¡La práctica te hará un experto en la construcción de software a prueba de fallos!