Historia de la cuestión:
El sistema de excepciones (exceptions) apareció en Python desde el principio y se basa en clases. Toda la jerarquía de excepciones hereda de la clase base BaseException. En la práctica, las excepciones propias se crean a partir de Exception. Desarrollar excepciones personalizadas es importante para proyectos grandes, ya que permite manejar y señalizar de manera más precisa errores específicos de la aplicación.
Problema:
No todos los desarrolladores entienden las diferencias entre BaseException y Exception, se deshacen de crear sus propias clases y utilizan bloques de captura generales, lo que lleva a absorber excepciones no deseadas (por ejemplo, SystemExit, KeyboardInterrupt) y errores difíciles de detectar. A menudo, las clases de excepciones se implementan incorrectamente: no se les asigna un nombre significativo y no heredan de la clase correcta.
Solución:
Escribir sus excepciones como herederos de Exception. Usar nombres significativos para no capturar errores básicos de forma indiscriminada. No heredar de BaseException, sino solo de Exception o sus derivados, y no capturar todo a través de except: sin especificar una clase concreta.
Ejemplo de código:
class MyAppError(Exception): """Clase base para excepciones de la aplicación""" pass class ConfigFileNotFound(MyAppError): pass try: raise ConfigFileNotFound('¡Archivo de configuración no encontrado!') except ConfigFileNotFound as e: print(f'Error: {e}')
Características clave:
¿Cuál es el peligro de capturar todas las excepciones a través de "except:" sin especificar un tipo?
Tal bloque captura incluso excepciones del sistema: KeyboardInterrupt, SystemExit, lo que imposibilita la finalización normal del programa al presionar Ctrl+C y puede llevar a "congelaciones" en situaciones críticas. Se debe escribir "except Exception:" para omitir eventos del sistema básicos.
¿Es posible heredar su excepción de BaseException?
Técnicamente es posible, pero se desaconseja categóricamente: tales excepciones son difíciles de detectar, eluden los manejadores estándar de Exception, lo que a menudo conduce a errores que no se pueden atrapar en la aplicación.
¿Es correcto utilizar ValueError o TypeError en lugar de excepciones personalizadas?
En scripts pequeños es aceptable, pero en proyectos grandes es mejor crear sus excepciones semánticamente significativas. Esto acelera el diagnóstico y el manejo de errores en los niveles superiores de la aplicación.
# Incorrecto: raise ValueError('Algo específico para la aplicación') # Bueno: class MyAppValueError(MyAppError): pass raise MyAppValueError('Descripción del error con contexto de la aplicación')
En un gran proyecto había un bloque global try/except: que capturaba también excepciones del sistema. Una serie de errores (como SystemExit) no se registraban en el log, la aplicación entraba en estados inesperados y los administradores buscaban síntomas durante mucho tiempo.
Ventajas:
Desventajas:
Se definieron clases de error propias, se utilizó siempre "except Exception: ..." y controladores separados para las excepciones personalizadas.
Ventajas:
Desventajas: