Apariencia
📙 Clase 12 — Excepciones: try / except
Fase 2 · Funciones y código organizado ⬅️ Volver al índice de clases
🎯 Qué aprendí
- Atrapar errores con
try/exceptpara que la app no se caiga. - Los tipos de excepción que ya conozco (
ValueError,KeyError,IndexError…). else/finally, lanzar errores propios conraise, y validar entradas del usuario en la GUI.
📖 PARTE TEÓRICA
💥 1. ¿Qué es una excepción?
Cuando algo sale mal en tiempo de ejecución, Python lanza una excepción: el programa se detiene y muestra un traceback. Ya conoces varias:
| Excepción | Cuándo salta | Ya la viste en |
|---|---|---|
ValueError | valor con tipo correcto pero contenido inválido: int("abc") | tu error real de tkinter |
KeyError | clave inexistente: dic["no_existe"] | Clase 04 |
IndexError | índice fuera de rango: lista[100] | Clase 01 |
TypeError | operación con tipo equivocado: (1,2)[0] = 9 | Clase 05 |
ZeroDivisionError | 10 / 0 | — |
NameError | variable que no existe | Clase 10 |
🛡️ 2. try / except: atrapar en vez de morir
python
try:
edad = int("abc") # esto EXPLOTA…
except ValueError as e:
print("Atrapado:", e) # …pero lo atrapamos y el programa SIGUE
# Atrapado: invalid literal for int() with base 10: 'abc'El patrón útil de verdad — una función que convierte "con red de seguridad":
python
def convertir(texto):
try:
return int(texto)
except ValueError:
return None # señal de "no se pudo"
print(convertir("42")) # 42
print(convertir("x")) # None ← el que llama decide qué hacer⚠️ Atrapa lo específico.
except ValueError:✅. Unexcept:pelado (oexcept Exception:sin motivo) esconde todos los errores, incluidos tus bugs — luego no sabes por qué "no hace nada". Regla: atrapa solo lo que sabes manejar.
🧱 3. La estructura completa: else y finally
python
try:
n = int("7")
except ValueError:
print("número inválido") # SOLO si hubo error
else:
print("sin error, n =", n) # SOLO si NO hubo error
finally:
print("esto corre SIEMPRE") # haya o no error (limpieza: cerrar archivos/conexiones)
# sin error, n = 7
# esto corre SIEMPREtry: lo que puede fallar
except: ├─ si FALLÓ → manejar
else: ├─ si NO falló → continuar
finally: └─ SIEMPRE → limpiar📣 4. raise: lanzar tus propios errores
Tu propia lógica también puede rechazar datos inválidos lanzando una excepción:
python
def poner_edad(edad):
if edad < 0:
raise ValueError("La edad no puede ser negativa")
return edad
try:
poner_edad(-5)
except ValueError as e:
print(e) # La edad no puede ser negativa🧪 Tip de entrevista: "¿Diferencia entre error de sintaxis y excepción?" → El de sintaxis impide arrancar el programa (
SyntaxErroral parsear); la excepción ocurre en ejecución y puede atraparse contry/except.
🖥️ EN TU APP DE ESCRITORIO
En una GUI, una excepción no atrapada dentro de un callback hace que la acción falle en silencio (el traceback se va a la consola y el usuario no ve nada). El patrón profesional: atrapar y avisar amablemente.
python
def calcular():
try:
cantidad = int(entry_cantidad.get()) # el usuario pudo escribir "abc"
except ValueError:
label_error.configure(text="⚠️ Ingresa un número válido", text_color="red")
return # early return (Clase 08)
label_error.configure(text="") # limpiar el aviso
label_total.configure(text=f"Total: {cantidad * 10}")El flujo del especialista:
entrada del usuario ─▶ try convertir/validar ─▶ ¿falló?
├─ sí → mensaje amable en la GUI + return
└─ no → ejecutar la acción💡 Conecta con tus errores reales: en vez de que la app muera con un
ValueError, ahora la atrapas y muestras un mensaje. Cada error de tu carpeta06-Errores/es un candidato atry/exceptbien puesto.
🗄️ CON BASE DE DATOS (caso de uso)
Las operaciones de BD pueden fallar (archivo bloqueado, tabla inexistente, dato duplicado). sqlite3 tiene su propia familia de excepciones:
python
import sqlite3
try:
con = sqlite3.connect("app.db")
con.execute("INSERT INTO contactos (email) VALUES (?)", ("ana@x.com",))
con.commit()
except sqlite3.IntegrityError:
print("Ese email ya existe (columna UNIQUE)") # → mensaje en la GUI
except sqlite3.Error as e:
print("Error de base de datos:", e) # cualquier otro problema de BD
finally:
con.close() # SIEMPRE cerrar la conexión🗄️
finally: con.close()es el uso clásico definally. En la Fase 5 verás la forma aún más elegante: el bloquewith(context managers).
🏋️ EJERCICIOS CON SOLUCIÓN
Ejercicio 1 — División segura
Escribe dividir(a, b) que devuelva a / b, o None si b es 0 (atrapando la excepción, no con if).
Ver solución
python
def dividir(a, b):
try:
return a / b
except ZeroDivisionError:
return None
print(dividir(10, 2)) # 5.0
print(dividir(10, 0)) # NoneEjercicio 2 — Entrada de formulario
Escribe leer_edad(texto) que devuelva (True, edad) si el texto es un entero entre 0 y 120, o (False, mensaje) si no. Usa try/except + validación.
Ver solución
python
def leer_edad(texto):
try:
edad = int(texto)
except ValueError:
return False, "Debe ser un número"
if not 0 <= edad <= 120:
return False, "Edad fuera de rango"
return True, edad
print(leer_edad("30")) # (True, 30)
print(leer_edad("abc")) # (False, 'Debe ser un número')
print(leer_edad("200")) # (False, 'Edad fuera de rango')Ejercicio 3 — Rechazar con raise
Escribe retirar(saldo, monto) que lance ValueError("Fondos insuficientes") si monto > saldo, y si no devuelva el nuevo saldo. Atrápalo al llamarla.
Ver solución
python
def retirar(saldo, monto):
if monto > saldo:
raise ValueError("Fondos insuficientes")
return saldo - monto
try:
retirar(100, 500)
except ValueError as e:
print(e) # Fondos insuficientes
print(retirar(100, 30)) # 70❓ Preguntas y respuestas (autoevaluación)
1. ¿Qué excepción lanza int("hola")?
ValueError(tipo correcto — string —, contenido inválido para convertir).
2. ¿Cuándo corre el bloque finally?
Siempre: haya o no excepción. Es para limpieza (cerrar archivos, conexiones).
3. ¿Por qué es mala idea un except: pelado?
Atrapa todo, incluidos bugs tuyos, y los esconde. Atrapa solo excepciones específicas que sabes manejar.
4. ¿Para qué usas raise en tu propia lógica?
Para rechazar datos/estados inválidos con un error claro que el llamador pueda atrapar.
📎 Apuntes relacionados
- Tus errores reales documentados → 06-Errores
- Early return al validar → Clase 08 · return
.get()como alternativa alKeyError→ Clase 04 · Diccionarios
➡️ Siguiente
¡Fase 2 lista! 🎉 Sigue la Fase 3 · POO: Clase 13 · Clases y objetos.