Cuándo y cómo verificar que las subclases de Python cumplan con las especificaciones.
Tengo una clase base que se ve algo así:
class myBaseClass:
def __init__(self):
self.name = None # Todas las subclases deben definir esto
def foo(self): # Todas las subclases deben definir esto
raise NotImplementedError
def bar(self): # Opcional -- no todas las subclases definirán esto
raise NotImplementedError
Mi especificación de API estipula que cualquier persona que cree una subclase de myBaseClass
debe proporcionar un valor significativo para .name
, y para la función .foo()
. Sin embargo, .bar()
es opcional y el código que lo llama debe poder manejar el caso en el que eso resulte en un NotImplementedError
.
¿Cuándo y cómo debo verificar que las subclases contribuidas por terceros cumplan con estos requisitos?
Las opciones parecen ser:
– Construir subclases exclusivamente a través de metaclasses. Sin embargo, este enfoque será desconocido y potencialmente confuso para la mayoría de los colaboradores de mi proyecto, que no suelen ser desarrolladores expertos.
– Añadir un método __init_subclass__
a la clase base y utilizar esto para inferir si la subclase ha sobrescrito todo lo que se supone que debe sobrescribir. Parece funcionar, pero se siente un poco ‘chapucero’.
– Escribir pruebas de tiempo de compilación para instanciar cada subclase, llamar a cada método ‘requerido’ y verificar que no arrojen un NotImplementedError. Parece ser un esfuerzo computacional excesivo para responder una pregunta tan simple (llamar a .foo()
puede ser costoso).
– Ignorar el problema. Lidiar con él si y cuando cause que algo más se rompa.
Estoy seguro de que no soy la única persona que necesita lidiar con este problema, ¿hay un enfoque ‘correcto’ aquí?
davy.ai
No hay un enfoque “correcto” para verificar que las subclases de
miClaseBase
cumplan con los requisitos. Sin embargo, algunas opciones que se pueden considerar son:__init_subclass__
: Esto te permite inferir si la subclase ha reemplazado todo lo que se supone que debe reemplazar. Puede parecer un poco “chapucero”, pero es un enfoque común y se recomienda en la documentación oficial de Python. Además, es lo suficientemente simple como para que incluso desarrolladores no expertos puedan entenderlo.Escribir pruebas en tiempo de compilación: Esto asegura que cada subclase cumpla con los requisitos antes de que se lance el código. Sin embargo, puede ser computacionalmente costoso y potencialmente ralentizar el proceso de compilación. Además, llamar a
.foo()
puede ser costoso, como mencionaste.Ignorar el problema: Esto puede ser tentador, pero significa que no hay garantía de que las subclases cumplan con los requisitos. Esto podría causar problemas más adelante.
En última instancia, el enfoque que elijas dependerá de los requisitos y limitaciones específicas de tu proyecto. Sin embargo, usar
__init_subclass__
es un enfoque común y recomendado por la documentación de Python.