Aprende leyendo en orden

Lanzar excepciones con raise / clases de excepción personalizadas

Aprende a lanzar tus propias excepciones en Python con raise y a definir clases de excepción personalizadas.

En el artículo anterior sobre try / except, vimos el lado receptor de una excepción.

Este artículo cubre raise — el lado emisor, donde haces aflorar una excepción tú mismo. Cuando lanzas una excepción ante una entrada inválida o un estado inesperado, se garantiza que el que llama se enterará vía try / except.

Lo básico de raise

Escribir raise ClaseDeExcepción("mensaje") lanza esa excepción justo en ese momento. En cuanto raise se ejecuta, el resto del código se salta y el control salta al except que coincida.

El mensaje es opcional, pero incluir por qué falló permite al receptor leerlo vía except ... as e.

Flujo raise → except
ejecutar cuerpo tryraise ValueError("...")(resto de try saltado)except ValueError as ee recibe el mensajeseguir ejecutandosaltar
# Lanza un ValueError y captúralo en el lado receptor
try:
    raise ValueError("Edad inválida")
    print("nunca se alcanza")
except ValueError as e:
    print(f"Capturado: {e}")
# Salida: Capturado: Edad inválida

# Cualquier excepción integrada funciona tal cual
# Comunes: ValueError / TypeError / KeyError / IndexError

Haz el viaje de ida y vuelta más pequeño posible con raise y try / except.

① Dentro de try, ejecuta raise KeyError("user_id no encontrado").

② Captúralo con except KeyError as e: e imprime "Tipo: KeyError / Detalles: {e}" en una línea.

③ Después de try / except, llama a print("Continuando…") para confirmar que el programa no se detuvo.

(La explicación aparece una vez que ejecutes el código correctamente.)

Editor Python

Ejecutar el código para ver el resultado

Validar con if + raise

raise se usa con más frecuencia para la validación de entrada. Cuando un if detecta algo inválido, raise de inmediato y devuelve la llamada al que la hizo. Es una técnica idiomática en funciones (se ve más adelante), donde lanzar dentro de una función notifica al que llama de argumentos incorrectos.

El flujo — el camino normal pasa de largo; el camino anómalo lanza y se detiene — es el patrón central para la validación en código de producción.

Flujo de validación con if + raise
recibir entradacond 1: ¿valor inválido?raise ValueError(...)cond 2: ¿tipo inválido?raise TypeError(...)todas las comprobaciones pasanejecutarprocesamiento normalel exceptdel llamante lo capturaNoNo

Comprueba la entrada una condición a la vez; en el instante en que algo falla, raise y para. Solo cuando todas las condiciones pasan se procede con el procesamiento normal. Como gana el primer raise, el orden de las comprobaciones marca su prioridad.

# Valida el precio de un producto: 0 o menos es un error
price = -500

try:
    if price < 0:
        raise ValueError(f"El precio debe ser 0 o mayor (se recibió: {price})")
    if not isinstance(price, int):
        raise TypeError(f"El precio debe ser entero (tipo recibido: {type(price).__name__})")
    print(f"Registrado: {price}")
except ValueError as e:
    print(f"Error de valor: {e}")
except TypeError as e:
    print(f"Error de tipo: {e}")
# Salida: Error de valor: El precio debe ser 0 o mayor (se recibió: -500)

Una guía rápida sobre qué excepción integrada lanzar: usa ValueError cuando el valor sea incorrecto, TypeError cuando el tipo no coincida con lo esperado, y KeyError / IndexError cuando la clave o el elemento objetivo falte en un dict o lista.

Valida un nombre de usuario.

① Define user_name = "".

② Dentro de try, lanza ValueError("El nombre de usuario es obligatorio") cuando user_name sea una cadena vacía, y ValueError("El nombre de usuario debe tener 20 caracteres o menos") cuando len(user_name) > 20. Si ninguno es el caso, imprime "Registrado: {user_name}".

③ Captura con except ValueError as e: e imprime "Error de entrada: {e}".

Editor Python

Ejecutar el código para ver el resultado

Definir una clase de excepción personalizada

A veces las excepciones integradas por sí solas hacen difícil saber qué validación falló. Definir tu propia clase de excepción te permite capturarla con precisión en el lado del except.

La forma es class NombreError(Exception): con pass (vacío) como cuerpo — eso es todo. Cubriremos las clases en profundidad en el próximo capítulo de programación orientada a objetos, pero para clases de excepción esta única línea basta.

Definir y usar una clase de excepción personalizada
Exception(padre integrado)class OutOfStockError(Exception): passraise OutOfStockError("sin stock")except OutOfStockError as e:extraer el aviso desde eseguir ejecutandofijar como padre (definir)usar el tipo
# Define una excepción personalizada (basta 1 línea)
class InvalidAgeError(Exception):
    pass

class DuplicateUserError(Exception):
    pass

registered_users = ["ana", "carlos"]
new_user = "ana"
new_age = -1

try:
    if new_age < 0:
        raise InvalidAgeError(f"La edad debe ser 0 o mayor: {new_age}")
    if new_user in registered_users:
        raise DuplicateUserError(f"Ya registrado: {new_user}")
    print(f"Registrado: {new_user}")
except InvalidAgeError as e:
    print(f"Error de edad: {e}")
except DuplicateUserError as e:
    print(f"Error de duplicado: {e}")
# Salida: Error de edad: La edad debe ser 0 o mayor: -1

Las excepciones personalizadas fijan Exception como clase padre

El Exception entre paréntesis nombra a la clase padre. Poner Exception ahí hace que tu clase personalizada obtenga automáticamente las características estándar de excepción — puede llevar un mensaje, es capturable por un except Exception genérico, etcétera. El mecanismo padre / hijo en sí (la herencia) se cubre en el capítulo de programación orientada a objetos, pero esta única línea es todo lo que necesitas para definir una excepción.

Crea una excepción dedicada a «sin stock» y lánzala durante un flujo de compra.

① Define class OutOfStockError(Exception): pass.

② Configura stock = {"manzana": 3, "pan": 0} y want = "pan".

③ En try, cuando stock[want] == 0, lanza OutOfStockError(f"Sin stock: {want}"); en caso contrario imprime "Comprado: {want}".

④ Captura con except OutOfStockError as e: e imprime "Aviso: {e}".

Editor Python

Ejecutar el código para ver el resultado

En este artículo aprendiste cómo lanzar excepciones tú mismo con raise, el patrón if + raise para la validación, y cómo definir una clase de excepción personalizada con Exception fijada como clase padre.

A continuación, miraremos def — que ya ha aparecido varias veces — como tema de primera categoría y aprenderemos a agrupar y reutilizar lógica con funciones.

QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Qué imprime el siguiente código?
try:
raise ValueError("NG")
print("A")
except ValueError as e:
print(e)
print("B")

Pregunta 2¿Qué excepción integrada es la más apropiada cuando el valor es inválido?

Pregunta 3¿Cuál es el mayor beneficio de usar una excepción personalizada class MyError(Exception): pass?