Podemos pensar en OOP como modelado el comportamiento de un sistema. Tenga en cuenta que el sistema no tiene que existir en el 'mundo real', aunque las metáforas del mundo real a veces pueden ser útiles (por ejemplo, "tuberías", "fábricas", etc.).
Si nuestro sistema deseado es demasiado complicado para modelarlo todo al mismo tiempo, podemos dividirlo en pedazos más pequeños y modelarlos (el "dominio del problema"), lo que puede implicar descomponerlo más, y así sucesivamente hasta que lleguemos a pedazos cuyo comportamiento coincide (más o menos) con el de algún objeto de lenguaje incorporado como un número, una cadena, una lista, etc.
Una vez que tengamos esas piezas simples, podemos combinarlas para describir el comportamiento de las piezas más grandes, que podemos combinar juntas en piezas aún más grandes, y así sucesivamente hasta que podamos describir todos los componentes del dominio que son necesarios. para todo un sistema.
Es esta fase de "combinación" donde podríamos escribir algunas clases. Escribimos clases cuando no hay un objeto existente que se comporte de la manera que queremos. Por ejemplo, nuestro dominio puede contener "foos", colecciones de foos llamadas "barras" y colecciones de barras llamadas "bazs". Podríamos notar que los foos son lo suficientemente simples para modelar con cuerdas, así que hacemos eso. Descubrimos que las barras requieren que su contenido obedezca a alguna restricción en particular que no coincide con lo que Python proporciona, en cuyo caso podríamos escribir una nueva clase para imponer esta restricción. Tal vez los bazs no tengan tales peculiaridades, por lo que podemos representarlos con una lista.
Tenga en cuenta que podríamos escribir una nueva clase para cada uno de esos componentes (foos, barras y bazs), pero no necesitamos si ya hay algo Con el comportamiento correcto. En particular, para que una clase sea útil, necesita "proporcionar" algo (datos, métodos, constantes, subclases, etc.), por lo que incluso si tenemos muchas capas de clases personalizadas, debemos finalmente usar alguna característica incorporada; por ejemplo, si escribiéramos una nueva clase para foos, probablemente solo contendría una cadena, ¿por qué no olvidar la clase foo y hacer que la clase bar contenga esas cadenas en su lugar? Tenga en cuenta que las clases también son un objeto incorporado, son simplemente uno especialmente flexible.
Una vez que tengamos nuestro modelo de dominio, podemos tomar instancias particulares de esas piezas y organizarlas en una "simulación" del sistema en particular que queremos modelar (por ejemplo, "un sistema de aprendizaje automático para ... ").
Una vez que tengamos esta simulación, podemos ejecutarla y, listo, tenemos un sistema de aprendizaje automático (simulación de a) para ... (o cualquier otra cosa que estemos modelando).
Ahora, en su situación particular, está intentando modelar el comportamiento de un componente "extractor de características". La pregunta es, ¿hay algún objeto incorporado que se comporte como un "extractor de características", o tendrá que dividirlo en cosas más simples? Parece que los extractores de características se comportan de manera muy parecida a los objetos de función, por lo que creo que sería bueno usarlos como modelo.
Una cosa que se debe tener en cuenta al aprender sobre este tipo de conceptos es que los diferentes idiomas pueden proporcionar diferentes características y objetos integrados (y, por supuesto, algunos ni siquiera usan terminología como "objetos"). Por lo tanto, las soluciones que tienen sentido en un idioma podrían ser menos útiles en otro (¡esto incluso puede aplicarse a diferentes versiones del mismo idioma!).
Históricamente, un lote de la literatura de OOP (especialmente "patrones de diseño") se ha centrado en Java, que es bastante diferente de Python. Por ejemplo, las clases de Java no son objetos, Java no tenía objetos de función hasta hace muy poco tiempo, Java tiene una comprobación de tipos estricta (lo que fomenta las interfaces y subclases), mientras que Python fomenta la tipificación de pato, Java no tiene objetos de módulo, enteros Java carrozas / etc no son objetos, la meta-programación / introspección en Java requiere "reflexión", y así sucesivamente.
No estoy tratando de elegir Java (como otro ejemplo, mucha teoría de la POO se basa en Smalltalk, que a su vez es muy diferente de Python), solo estoy tratando de señalar que debemos pensar con mucho cuidado el contexto y las limitaciones en las que se desarrollaron las soluciones, y si esto coincide con la situación en la que nos encontramos.
En su caso, un objeto de función parece ser una buena opción. Si se está preguntando por qué algunas pautas de "mejores prácticas" no mencionan los objetos de función como una posible solución, ¡podría ser simplemente porque esas directrices se escribieron para versiones antiguas de Java!