Manejo de errores como un profesional: Excepciones, logging y debugging en Python

Manejo de Errores Profesional en Python: Excepciones, Logging y Debugging

Introducción al Manejo de Errores en Python

El manejo robusto de errores es esencial para desarrollar aplicaciones confiables. En este tutorial cubriremos:

  • Filosofías EAFP vs LBYL
  • Jerarquía de excepciones
  • Creación de excepciones personalizadas
  • Uso estratégico de logging
  • Herramientas avanzadas de debugging

1. Filosofías de Manejo de Errores

EAFP (Easier to Ask for Forgiveness than Permission)

try:
    with open('archivo.txt') as f:
        contenido = f.read()
except FileNotFoundError:
    print("El archivo no existe")

LBYL (Look Before You Leap)

import os

if os.path.exists('archivo.txt'):
    with open('archivo.txt') as f:
        contenido = f.read()
else:
    print("El archivo no existe")

Cuándo usar cada enfoque:

  • EAFP: Ideal para Python (idiomático)
  • LBYL: Útil cuando las verificaciones son económicas

2. Jerarquía de Excepciones

Principales excepciones built-in:

BaseException
 ├── SystemExit
 ├── KeyboardInterrupt
 ├── Exception
      ├── ArithmeticError
      ├── LookupError
      ├── OSError
      └── RuntimeError

3. Excepciones Personalizadas

class ErrorDeValidacion(Exception):
    """Error cuando falla la validación de datos"""

    def __init__(self, mensaje, codigo_error):
        super().__init__(mensaje)
        self.codigo_error = codigo_error

def validar_edad(edad):
    if edad < 0:
        raise ErrorDeValidacion("La edad no puede ser negativa", 1001)

4. Bloques Try/Except Avanzados

try:
    resultado = 10 / divisor
except ZeroDivisionError:
    print("Error: División por cero")
except TypeError:
    print("Error: Tipo de dato incorrecto")
else:
    print(f"Resultado: {resultado}")
finally:
    print("Ejecución finalizada")

5. Context Managers para Manejo de Recursos

Implementación personalizada:

class GestorDB:
    def __enter__(self):
        self.conexion = crear_conexion_db()
        return self.conexion

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            print(f"Error: {exc_val}")
        self.conexion.close()

6. Configuración Profesional de Logging

import logging
from logging.handlers import RotatingFileHandler

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# Configuración de handlers
console_handler = logging.StreamHandler()
file_handler = RotatingFileHandler('app.log', maxBytes=1e6, backupCount=3)

# Formato
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

# Añadir handlers
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# Ejemplo de uso
logger.info("Iniciando aplicación")
try:
    1 / 0
except Exception:
    logger.exception("Error crítico")

7. Herramientas de Debugging

PDB (Python Debugger)

import pdb

def funcion_problematica():
    pdb.set_trace()  # Punto de interrupción
    # Código a depurar

cProfile para Análisis de Rendimiento

python -m cProfile mi_script.py

8. Ejemplos Prácticos

Cliente HTTP con Reintentos

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()
retries = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[500, 502, 503, 504]
)
session.mount('https://', HTTPAdapter(max_retries=retries))

Validación de Datos con Excepciones

def procesar_datos(datos):
    if not isinstance(datos, dict):
        raise TypeError("Se esperaba un diccionario")
    if 'clave' not in datos:
        raise ValueError("Falta clave obligatoria")
    # Procesamiento...

9. Anti-patrones Comunes

Captura demasiado amplia:

try:
    # código
except:  # ¡Evitar!
    pass

Mejor práctica:

try:
    # código
except ValueError as e:
    logger.error(f"Error de valor: {e}")

10. Buenas Prácticas

  1. Específica en las excepciones: Captura solo los errores que esperas
  2. Registra adecuadamente: Proporciona contexto en los logs
  3. Prueba los casos de error: Implementa unit tests para flujos de error
  4. Documenta los errores: Comenta qué excepciones puede lanzar cada función

Conclusión

El manejo profesional de errores implica:

  • Uso adecuado de excepciones
  • Logging estratégico
  • Técnicas efectivas de debugging
  • Implementación de patrones robustos

Recursos adicionales:

¡Ahora estás listo para manejar errores como un profesional en Python! 🚀


Publicado

en

por

Etiquetas:

Comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *