We can think of OOP as modelling the behaviour of a system. Note that the system doesn't have to exist in the 'real world', although real-world metaphors can sometimes be useful (e.g. "pipelines", "factories", etc.).
If our desired system is too complicated to model all at once, we can break it down into smaller pieces and model those (the "problem domain"), which may involve breaking down further, and so on until we get to pieces whose behaviour matches (more or less) that of some built-in language object like a number, a string, a list, etc.
Once we have those simple pieces, we can combine them together to describe the behaviour of larger pieces, which we can combine together into even larger pieces, and so on until we can describe all of the components of the domain that are needed for a whole system.
It is this "combining together" phase where we might write some classes. We write classes when there isn't an existing object which behaves in the way we want. For example, our domain might contain "foos", collections of foos called "bars", and collections of bars called "bazs". We might notice that foos are simple enough to model with strings, so we do that. We find that bars require their contents to obey some particular constraint which doesn't match anything Python provides, in which case we might write a new class to enforce this constraint. Perhaps bazs have no such peculiarities, so we can just represent them with a list.
Note that we could write a new class for every one of those components (foos, bars and bazs), but we don't need to if there's already something with the correct behaviour. In particular, for a class to be useful it needs to 'provide' something (data, methods, constants, subclasses, etc.), so even if we have many layers of custom classes we must eventually use some built-in feature; for example, if we wrote a new class for foos it would probably just contain a string, so why not forget the foo class and have the bar class contain those strings instead? Keep in mind that classes are also a built-in object, they're just a particularly flexible one.
Once we have our domain model, we can take some particular instances of those pieces and arrange them into a "simulation" of the particular system that we want to model (e.g. "a machine learning system for ...").
Once we have this simulation, we can run it and hey presto, we have a working (simulation of a) machine learning system for ... (or whatever else we were modelling).
Now, in your particular situation you're trying to model the behaviour of a "feature extractor" component. The question is, are there any built-in objects which behave like a "feature extractor", or will you need to break it up into simpler things? It looks like feature extractors behave very much like function objects, so I think you'd be fine to use those as your model.
One thing to keep in mind when learning about these sorts of concepts is that different languages can provide different built-in features and objects (and, of course, some don't even use terminology like "objects"!). Hence solutions which make sense in one language might be less useful in another (this can even apply to different versions of the same language!).
Historically, a lot of the OOP literature (especially "design patterns") has focused on Java, which is quite different from Python. For example, Java classes are not objects, Java didn't have function objects until very recently, Java has strict type checking (which encourages interfaces and subclassing) whilst Python encourages duck-typing, Java doesn't have module objects, Java integers/floats/etc. aren't objects, meta-programming/introspection in Java requires "reflection", and so on.
I'm not trying to pick on Java (as another example, a lot of OOP theory revolves around Smalltalk, which is again very different from Python), I'm just trying to point out that we must think very carefully about the context and constraints in which solutions were developed, and whether that matches the situation we're in.
In your case, a function object seems like a good choice. If you're wondering why some "best practice" guideline doesn't mention function objects as a possible solution, it might simply be because those guidelines were written for old versions of Java!