Podemos pensar em POO como modelagem do comportamento de um sistema. Observe que o sistema não precisa existir no 'mundo real', embora as metáforas do mundo real às vezes possam ser úteis (por exemplo, "pipelines", "factory" etc.).
Se o nosso sistema desejado for muito complicado para modelar tudo de uma vez, podemos decompô-lo em partes menores e modelá-las (o "domínio do problema"), o que pode envolver uma quebra ainda maior e assim por diante, até que cheguemos a peças cujo comportamento coincide (mais ou menos) o de algum objeto de linguagem embutido, como um número, uma string, uma lista etc.
Quando tivermos essas peças simples, podemos combiná-las para descrever o comportamento de peças maiores, as quais podemos combinar em peças ainda maiores, e assim por diante até podermos descrever todos os componentes do domínio necessários para um todo sistema.
É nessa fase de "combinação" que podemos escrever algumas aulas. Nós escrevemos classes quando não há um objeto existente que se comporte da maneira que queremos. Por exemplo, nosso domínio pode conter "foos", coleções de foos chamadas "bars" e coleções de barras chamadas "bazs". Podemos notar que os foos são simples o suficiente para modelar com strings, então fazemos isso. Nós descobrimos que as barras exigem que seu conteúdo obedeça a alguma restrição específica que não corresponde a nada que o Python fornece; nesse caso, podemos escrever uma nova classe para impor essa restrição. Talvez os bazs não tenham essas peculiaridades, então podemos representá-los com uma lista.
Observe que poderíamos escrever uma nova classe para cada um desses componentes (foos, bars e bazs), mas não precisamos se já houver algo com o comportamento correto. Em particular, para que uma classe seja útil, ela precisa 'fornecer' alguma coisa (dados, métodos, constantes, subclasses etc.), portanto, mesmo que tenhamos muitas camadas de classes personalizadas, devemos usar algum recurso interno; por exemplo, se escrevêssemos uma nova classe para foos, provavelmente ela conteria apenas uma string. Por que não esquecer a classe foo e fazer com que a classe bar contenha essas strings? Lembre-se de que as classes também são um objeto interno, mas são particularmente flexíveis.
Depois de termos nosso modelo de domínio, podemos pegar algumas instâncias particulares dessas partes e organizá-las em uma "simulação" do sistema específico que queremos modelar (por exemplo, "um sistema de aprendizado de máquina para ...").
Uma vez que tenhamos essa simulação, podemos executá-la e, e pronto, temos um (simulação de a) sistema de aprendizado de máquina para ... (ou qualquer outra coisa que estávamos modelando).
Agora, em sua situação específica, você está tentando modelar o comportamento de um componente "extrator de recursos". A questão é: existem objetos embutidos que se comportam como um "extrator de recursos" ou será necessário dividi-lo em coisas mais simples? Parece que os extratores de recursos se comportam muito como objetos de função, então acho que você pode usá-los como modelo.
Uma coisa a ter em mente ao aprender sobre esses tipos de conceitos é que linguagens diferentes podem fornecer diferentes recursos e objetos internos (e, é claro, alguns nem usam terminologia como "objetos"!). Portanto, soluções que fazem sentido em um idioma podem ser menos úteis em outro (isso pode até se aplicar a diferentes versões do mesmo idioma!).
Historicamente, grande parte da literatura OOP (especialmente "padrões de design") se concentrou em Java, que é bem diferente do Python. Por exemplo, classes Java não são objetos, Java não possuía objetos de função até muito recentemente, Java possui verificação estrita de tipo (o que incentiva interfaces e subclasses), enquanto Python incentiva a digitação de patos, Java não possui objetos de módulo, números inteiros Java / carros alegóricos / etc. não são objetos, a metaprogramação / introspecção em Java requer "reflexão" e assim por diante.
Não estou tentando entender o Java (como outro exemplo, muita teoria de OOP gira em torno do Smalltalk, que é muito diferente do Python), apenas estou tentando ressaltar que devemos pensar com muito cuidado sobre o contexto e restrições nas quais as soluções foram desenvolvidas e se isso corresponde à situação em que estamos.
No seu caso, um objeto de função parece ser uma boa escolha. Se você está se perguntando por que algumas diretrizes de "melhores práticas" não mencionam objetos de função como uma possível solução, pode ser simplesmente porque essas diretrizes foram escritas para versões antigas do Java!