Podemos pensar em OOP como modelando o comportamento de um sistema. Note que o sistema não tem que existir no 'mundo real', embora metáforas do mundo real às vezes possam ser úteis (por exemplo, "pipelines", "factories", etc.).
Se o nosso sistema desejado é muito complicado para modelar tudo de uma vez, podemos dividi-lo em pedaços menores e modelá-los (o "domínio do problema"), o que pode envolver uma quebra ainda maior, e assim por diante. cujo comportamento corresponde (mais ou menos) a algum objeto de linguagem interno 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, que podemos combinar em partes maiores, e assim por diante, até que possamos descrever todos os componentes do domínio que são necessários para todo um sistema.
É essa fase de "combinar juntos" onde podemos escrever algumas classes. Nós escrevemos classes quando não há um objeto existente que se comporta da maneira que queremos. Por exemplo, nosso domínio pode conter "foos", coleções de foos chamadas "barras" e coleções de barras chamadas "bazs". Podemos notar que foos são simples o suficiente para modelar com strings, então fazemos isso. Descobrimos que as barras exigem que seus conteúdos obedeçam a alguma restrição específica que não corresponde a nada que o Python forneça, caso em que poderíamos escrever uma nova classe para impor essa restrição. Talvez os bazs não tenham tais peculiaridades, então podemos apenas representá-los com uma lista.
Note que nós poderíamos escrever uma nova classe para cada um desses componentes (foos, bars e bazs), mas nós não precisamos se já houver algo com o comportamento correto. Em particular, para uma classe ser útil, ela precisa 'fornecer' algo (dados, métodos, constantes, subclasses, etc.), portanto, mesmo que tenhamos muitas camadas de classes personalizadas, devemos usar eventualmente algum recurso interno; por exemplo, se escrevêssemos uma nova classe para foos, ela provavelmente conteria apenas uma string, então por que não esquecer a classe foo e ter a classe bar contendo essas strings? Tenha em mente que as classes também são um objeto embutido, elas são apenas particularmente flexíveis.
Uma vez que tenhamos nosso modelo de domínio, podemos tomar algumas instâncias dessas peças e organizá-las em uma "simulação" do sistema específico que queremos modelar (por exemplo, "um sistema de aprendizado de máquina". para ... ").
Assim que tivermos essa simulação, podemos executá-la e, pronto, temos um sistema de aprendizado de máquina em funcionamento (simulação de a) para ... (ou qualquer outro modelo que estivéssemos modelando).
Agora, na sua situação particular, você está tentando modelar o comportamento de um componente "extractor de recursos". A questão é, existem objetos embutidos que se comportam como um "extrator de recursos", ou você precisará dividi-los em coisas mais simples? Parece que os extratores de recursos se comportam muito como objetos de função, então eu acho que você estaria bem para usá-los como seu modelo.
Uma coisa a ter em mente ao aprender sobre esses tipos de conceitos é que diferentes linguagens podem fornecer diferentes recursos e objetos internos (e, é claro, alguns nem usam terminologia como "objetos"!). Portanto, as 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, um lote da literatura de OOP (especialmente "padrões de design") tem se concentrado em Java, que é bem diferente do Python. Por exemplo, as classes Java não são objetos, Java não tem objetos de função até muito recentemente, Java possui verificação de tipo estrita (que incentiva interfaces e subclasses) enquanto o Python incentiva a digitação de pato, Java não possui objetos de módulo, inteiros Java flutuadores / etc. não são objetos, meta-programação / introspecção em Java requer "reflexão" e assim por diante.
Eu não estou tentando escolher Java (como outro exemplo, muita teoria de OOP gira em torno de Smalltalk, que é novamente muito diferente do Python), estou apenas tentando mostrar que devemos pensar muito cuidadosamente sobre o contexto e as restrições em que 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 uma diretriz de "melhor prática" não menciona objetos de função como uma possível solução, pode ser simplesmente porque essas diretrizes foram escritas para versões antigas do Java!