Domina el manejo de errores en Python creando excepciones personalizadas que expresen la intención de tu código y mejoren la experiencia de otros desarrolladores. Con raise, try, except y finally, podrás detener la ejecución a tiempo, comunicar fallos específicos y decidir dónde y cómo mostrarlos.
Excepciones personalizadas en Python
Crear tus propias excepciones te permite nombrar el problema y facilitar su captura precisa. En lugar de devolver una lista vacía, puedes lanzar un error explícito para que quien consuma la funcionalidad decida el mensaje a mostrar.
¿Cómo funciona raise para detener la ejecución?
Usa raise para lanzar un error y frenar el flujo.
El bloque finally se ejecuta siempre, incluso si hay error.
Mensajes claros orientan al desarrollador: "no está permitido el cálculo por dos".
# Ejemplo inicial con la excepción genéricadefdividir(a, b):if b ==2:raise Exception("No está permitido el cálculo por dos")return a / b
try: dividir(100,2)except Exception as e:print(e)finally:print("finally siempre se ejecuta")
¿Por qué crear una excepción específica y no usar Exception?
Para capturar solo lo que importa y no "todo" con Exception.
Para documentar la intención del error mediante nombre y docstring.
classDivisionError(Exception):"""Error en operación."""passdefdividir(a, b):if b ==2:raise DivisionError("No está permitido el cálculo por dos")return a / b
try: dividir(100,2)except DivisionError as e:# captura específicaprint(e)finally:print("finally siempre se ejecuta")
Patrón try, except y finally
El flujo de manejo de errores se apoya en cuatro cláusulas usadas con intención: colocar lo frágil en try, decidir cuándo fallar con raise, capturar con except y garantizar limpieza con finally.
¿Qué hace cada cláusula en el flujo de errores?
try: bloque con código que podría fallar.
raise: detiene la ejecución y lanza un tipo de error específico.
except: captura un tipo de error concreto o todos si usas Exception.
finally: se ejecuta siempre, ocurra o no un error.
¿Cómo capturar y mostrar mensajes claros?
Captura el tipo correcto para evitar silencios o excesos.
Muestra el mensaje de la excepción con print(e).
Evita duplicar mensajes en consola.
try:# operación sensible resultado = dividir(100,2)except DivisionError as e:print(e)# mensaje claro y suficientefinally:print("limpieza de recursos, si aplica")
Caso aplicado con News API client
En lugar de retornar arrays vacíos, lanza errores que expresen el fallo real. Define una jerarquía de excepciones para tu cliente y maneja los errores donde consumes la funcionalidad.
¿Cómo definir una jerarquía de excepciones para la app?
Crea una base para agrupar errores de la aplicación.
Hereda casos específicos como ApiKey inválida.
Documenta con docstrings para guiar a otros.
classNewsSystemError(Exception):"""Error general en la app."""passclassApiKeyError(NewsSystemError):"""ApiKey inválida."""pass# En el cliente, en lugar de devolver lista vacíadeffetch_articles():# ... si falla la conexión con la APIraise NewsSystemError("Ocurrió un error, no se pudo conectar con la API")
¿Dónde y cómo manejar el error en el consumo?
Maneja el error donde llamas al cliente, con try/except.
Inicializa variables como response_data en None para evitar referencias no definidas.
Muestra solo el mensaje de la excepción para evitar repeticiones.
response_data =Nonetry: response_data = fetch_articles()except NewsSystemError as e:print(e)# "Ocurrió un error, no se pudo conectar con la API"if response_data isnotNone:# continuar con el flujo cuando hay datos válidospass
Ideas clave para aplicar hoy:
Excepciones personalizadas: nombres claros y captura específica.
raise: decide cuándo detener el flujo con un mensaje útil.
Jerarquía de errores: una base común más casos concretos.
Manejo en el consumidor: try/except cerca del uso real.
Estados seguros: inicializa a None y valida antes de usar.
¿Ya tienes una excepción personalizada para tu News API client? Compártela y cuéntanos cómo decidiste el nombre, el mensaje y dónde la capturas.
Para hacer la prueba de excepciones y agregar uno nuevo lo que hice fue investigar como se conforma urllib.error, el cual tiene una propiedad a la cual se puede acceder para obtener el error HTTP específico y generar un mensaje para cada tipo.
Por lo tanto implementé la siguiente clase:
class EndpointBadRequest(NewsSystemError):
"""Error cuando el endpoint request no está formado correctamente"""
pass
La cual se termina llamando de la siguiente forma dentro del bloque de try-except:
🧠MANEJO DE ERRORES EN PYTHON
🎯 OBJETIVO PRINCIPAL
Aprende a controlar errores con intención y claridad:
🚫 Detén la ejecución cuando sea necesario.
💬 Comunica el fallo exacto.
🧩 Facilita la vida a otros desarrolladores.
👉 Usa las herramientas: raise, try, except, finally
⚙️ CONCEPTOS CLAVE
🧨 raise
🔹 Lanza un error y detiene el flujo del programa.
🔹 Permite indicar qué salió mal.
🔹 Ejemplo de mensaje:
"No está permitido el cálculo por dos"
🔁 finally
🔹 Se ejecuta siempre, incluso si ocurre un error.
🔹 Ideal para:
cerrar archivos
liberar memoria
terminar conexiones
💡 EJEMPLO INICIAL
def dividir(a, b):
if b == 2:
raise Exception("No está permitido el cálculo por dos")
return a / b
try:
dividir(100, 2)
except Exception as e:
print(e)
finally:
print("finally siempre se ejecuta")
📘 Aquí el error se lanza con una excepción genérica.
🧩 EXCEPCIONES PERSONALIZADAS
Crea tus propias clases de error para capturar solo lo que importa
y expresar la intención del fallo.
🧱 ¿Por qué usarlas?
✅ Capturan errores específicos.
✅ Documentan mejor el propósito del fallo.
✅ Evitan atrapar todo con Exception.
✏️ Ejemplo práctico
class DivisionError(Exception):
"""Error en operación."""
pass
def dividir(a, b):
if b == 2:
raise DivisionError("No está permitido el cálculo por dos")
return a / b
try:
dividir(100, 2)
except DivisionError as e:
print(e)
finally:
print("finally siempre se ejecuta")
🔄 ESTRUCTURA DEL MANEJO DE ERRORES
try → código que puede fallar
raise → lanza el error
except → captura el error
finally → se ejecuta siempre
📍 Este patrón es la base del manejo controlado de errores.
Mi clase para URL error:
classAPIRequestError(NewsSystemError):"""Error durante la solicitud a la API."""
pass
Y por ultimo capturo la excepción, antes del HTTPError, ya que sino la detecta como tal y no salta el URLError.
def news_api_client(api_key, query, timeout=30, retries=3, language=DEFAULT_LANGUAGE): query_string = urllib.parse.urlencode({"q": query,"apiKey": api_key,"language": language}) url = f"{API_ENDPOINT}?{query_string}"try:with urllib.request.urlopen(url, timeout=timeout)asresponse: data = response.read().decode("utf-8")return json.loads(data) except urllib.error.URLError: raise APIRequestError("Ocurrio un error durante la solicitud a la API.") except urllib.error.HTTPError: raise APIKeyError("Ocurrió un error con la API Key.")return f"NewsApi: {query} con timeout {timeout}"response_data =Nonetry: response_data =fetch_news("newsapi", api_key=API_KEY, query="Python")except APIKeyErrorase:print(f"Error de API Key: {e}")except APIRequestErrorase:print(f"Error en la solicitud a la API: {e}")ifresponse_data:for article in response_data["articles"]:print(article["title"])
que tal amigo, porqué sucede esto? a mi tampoco me funcionaba hasta que cambien de posición como en tu ejemplo. saludos.
No tengo idea de como funciona esa sintaxis para esas clases... No importa aprenderé cuando vea el curso de POO con python. Sigamos!!!
Por ahora solo hay que saber que:
class es una palabra reservada
Te espero en el curso de programación orientada a objetos, ese está buenisimo!
Podría ocurrir que la API que estamos consumiendo tenga un RBAC y nuestro token no tenga autorización para acceder a ciertas noticias (por ejemplo por una capa de suscripción). En este caso la API nos podría devolver un error 401 que es "Unauthorized". Para capturar este error podríamos hacer lo siguiente:
classUnauthorizedError(NewsSystemError):"""Error para capturar token no autorizado""" pass
def news_api_client():...try:with urllib.request.urlopen(url, timeout=timeout)asresponse: data = response.read().decode("utf-8")return json.loads(data) except urllib.error.URLError: raise UnauthorizedError("Tu usuario no tiene autorización para acceder a este sitio")
eso es un caso avanzado pero bien que lo tengas en cuenta, de hecho creo que si una API hace eso en esos recursos podría ser confuso, puesto que una API deberia se idempotente
Entendido, muchas gracias por su respuesta!! En ese caso, tendría más sentido devolver un ForbiddenError (403)?