Menu

Excepciones en Python: try, except, else, finally y raise

Cómo manejar errores en Python — try/except/finally, capturar excepciones específicas, lanzar las tuyas y cuándo dejar que un error se propague.

Los errores son solo valores con mala actitud

Cuando algo va mal en Python — dividir por cero, leer un archivo que falta, parsear un número malo — el runtime crea un objeto excepción y empieza a desenrollar la pila de llamadas hasta que algo lo capture. Si nada lo hace, tu programa termina e imprime un traceback.

Las excepciones no son malas en sí. Son cómo Python señala "no puedo continuar con esta operación; aquí tienes el motivo". Tu trabajo es decidir, caso por caso, cuáles sabes cómo manejar y cuáles deberías dejar escalar.

La forma básica

main.py
Output
Click Run to see the output here.
  • try: abre el bloque de código arriesgado.
  • except ValueError: captura esa excepción específica si se lanza dentro del try.
  • Si no se lanza ninguna excepción, el except se salta por completo.

Ejecuta el fragmento con 42 — funciona. Ejecútalo con hello — corre el manejador.

Capturar excepciones específicas

Python tiene una jerarquía de tipos de excepción. Unas cuantas con las que te encontrarás a menudo:

  • ValueError — un valor estaba mal de alguna forma (int("abc"), argumentos fuera de rango).
  • TypeError — se usó el tipo equivocado ("hi" + 3).
  • KeyError — no se encontró una clave de dict.
  • IndexError — un índice de secuencia estaba fuera de rango.
  • FileNotFoundError — un archivo no existe.
  • ZeroDivisionError — se intentó dividir por cero.
  • AttributeError — un objeto no tiene el atributo pedido.

Captura la específica que sepas manejar:

main.py
Output
Click Run to see the output here.

Puedes capturar varias excepciones en una cláusula pasando una tupla:

main.py
Output
Click Run to see the output here.

Fíjate en as e. Eso ata el objeto excepción a e para que puedas inspeccionar su mensaje o atributos.

Evita capturar todo

Un except: a secas captura literalmente cualquier cosa, incluidos KeyboardInterrupt (tu Ctrl-C) y salidas a nivel de sistema. No lo uses.

except Exception: es un poco mejor, pero sigue siendo peligroso — se traga bugs que no anticipaste y oculta la fuente real de los problemas:

# No hagas esto sin una razón realmente buena.
try:
    do_something()
except Exception:
    pass

La jugada correcta es casi siempre capturar la excepción específica de la que sabes cómo recuperarte. Si una excepción que no esperabas llega al tope de tu programa, el traceback te dice exactamente qué fue mal — eso es una feature, no un bug.

else y finally

La sentencia try tiene dos cláusulas opcionales más:

  • else se ejecuta si el bloque try terminó sin lanzar.
  • finally se ejecuta sin importar qué — excepción o no.
main.py
Output
Click Run to see the output here.

else es el sitio más limpio para código "solo en éxito" — no quieres que un bloque try haga más que la parte que realmente puede fallar. finally es para limpieza que debe ejecutarse incluso si el try falla: cerrar un recurso, liberar un lock, restaurar estado.

Lanzar excepciones tú mismo

Usa raise para señalar un error en tu propio código:

main.py
Output
Click Run to see the output here.

Elige un tipo de excepción que encaje con lo que fue mal. Recurre a los incorporados primero — ValueError, TypeError, FileNotFoundError — antes de definir tu propia clase.

Definir tu propia excepción

Cuando los incorporados no capturan el significado, define una excepción personalizada:

main.py
Output
Click Run to see the output here.

Hereda de Exception (o de un incorporado más específico) y ponle una docstring a la clase. Eso suele ser todo lo que necesitas. Las excepciones personalizadas dejan a quien llama capturar solo el error que tiene sentido en su dominio.

raise ... from ...: excepciones encadenadas

Cuando una excepción dispara otra, mantén la cadena:

main.py
Output
Click Run to see the output here.

El from e adjunta el error original. Cuando el traceback se imprime, Python muestra ambos — el ConfigError que salió a la superficie y el FileNotFoundError que lo causó. Ese tipo de rastro es invaluable al depurar.

Context managers: la forma más limpia de limpiar

finally está bien, pero para recursos como archivos, un context manager (lo que usa with) es casi siempre mejor:

# versión con finally
f = open("data.txt")
try:
    data = f.read()
finally:
    f.close()

# versión con with
with open("data.txt") as f:
    data = f.read()

Ambas son seguras. La forma with es más corta y se aplica automáticamente. Recurre a finally solo cuando estés haciendo algo que la librería estándar no envuelve ya en un context manager.

Cuándo no capturar

Capturar una excepción es una decisión — estás diciendo "puedo manejar esto". Si no puedes, deja que la excepción se propague. Código como este es casi siempre un error:

try:
    do_work()
except Exception:
    pass  # ignorar silenciosamente todo

Silenciar errores hace invisibles los bugs. Es mejor crashear ruidosamente que cojear en un estado inconsistente.

Para cerrar

  • try/except te deja manejar errores de los que te puedes recuperar.
  • Captura excepciones específicas, no Exception a lo bruto.
  • raise señala errores en tu propio código.
  • Los bloques with reemplazan la mayor parte de limpieza con finally.
  • En caso de duda, deja que la excepción se propague.

Siguiente: un recorrido por los errores específicos que Python lanza más a menudo — KeyError, ValueError, ModuleNotFoundError y unos cuantos más — más los hábitos de depuración que los arreglan rápido.

Preguntas frecuentes

¿Cómo manejo errores en Python?

Envuelve código arriesgado en un bloque try y captura la excepción específica en un bloque except: try: risky() except ValueError: .... El else opcional se ejecuta si no ocurrió ninguna excepción; finally se ejecuta de una u otra forma, para limpieza.

¿Debería capturar Exception para ir sobre seguro?

No. Un except: a secas o except Exception: oculta bugs que no anticipaste. Captura la excepción específica de la que sepas recuperarte y deja que todo lo demás se propague para que veas el problema real.

¿Cuál es la diferencia entre raise y raise from?

raise NewError(...) lanza una excepción nueva. raise NewError(...) from original mantiene la excepción original adjunta como causa, que Python muestra en el traceback. Usa from cuando un error de bajo nivel haya disparado uno de alto nivel que quieres exponer.

Aprende a programar con Coddy

COMENZAR