Possiamo pensare a OOP come a modellare il comportamento di un sistema. Si noti che il sistema non deve esistere nel "mondo reale", sebbene a volte le metafore del mondo reale possano essere utili (ad esempio "condotte", "fabbriche", ecc.).
Se il nostro sistema desiderato è troppo complicato per modellare tutto in una volta, possiamo scomporlo in pezzi più piccoli e modellarli (il "dominio problematico"), che può comportare un ulteriore abbattimento, e così via fino a quando non arriviamo a pezzi il cui comportamento corrisponde (più o meno) quello di un oggetto linguaggio incorporato come un numero, una stringa, un elenco, ecc.
Una volta che abbiamo quei pezzi semplici, possiamo combinarli insieme per descrivere il comportamento di pezzi più grandi, che possiamo combinare insieme in pezzi ancora più grandi, e così via fino a quando non possiamo descrivere tutti i componenti del dominio necessari per un intero sistema.
È questa fase di "combinazione" in cui potremmo scrivere alcune classi. Scriviamo le classi quando non esiste un oggetto esistente che si comporti come vogliamo. Ad esempio, il nostro dominio potrebbe contenere "foos", raccolte di foos chiamate "bars" e raccolte di barre chiamate "bazs". Potremmo notare che i foo sono abbastanza semplici da modellare con le stringhe, quindi lo facciamo. Scopriamo che le barre richiedono che i loro contenuti obbediscano ad alcuni vincoli particolari che non corrispondono a nulla di ciò che Python fornisce, nel qual caso potremmo scrivere una nuova classe per far rispettare questo vincolo. Forse i baz non hanno tali peculiarità, quindi possiamo semplicemente rappresentarli con un elenco.
Nota che noi potremmo scrivere una nuova classe per ogni uno di quei componenti (Foos, bar e bazs), ma non hanno bisogno di se c'è già qualcosa con il comportamento corretto. In particolare, per una classe per essere utile deve 'offrire' qualcosa (dati, metodi, costanti, sottoclassi, ecc), quindi, anche se abbiamo molti strati di classi personalizzate ci dobbiamo finalmente usare qualche funzione integrata; per esempio, se scrivessimo una nuova classe per foos probabilmente conterrebbe solo una stringa, quindi perché non dimenticare la classe foo e fare in modo che la classe bar contenga quelle stringhe? Tieni presente che le classi sono anche un oggetto incorporato, sono solo particolarmente flessibili.
Una volta che abbiamo il nostro modello di dominio, possiamo prendere alcuni casi particolari di quei pezzi e disporli in una "simulazione" del sistema particolare che vogliamo modellare (ad esempio "un sistema di apprendimento automatico per ...").
Una volta che abbiamo questa simulazione, possiamo eseguirla e hey presto, abbiamo un sistema funzionante (simulazione di a) di machine learning per ... (o qualsiasi altra cosa stessimo modellando).
Ora, nella tua situazione particolare, stai cercando di modellare il comportamento di un componente "estrattore di funzioni". La domanda è: ci sono oggetti incorporati che si comportano come un "estrattore di funzioni" o dovrai scomporlo in cose più semplici? Sembra che gli estrattori di funzioni si comportino in modo molto simile agli oggetti funzione, quindi penso che andrebbe bene usarli come modello.
Una cosa da tenere a mente quando si imparano questi tipi di concetti è che linguaggi diversi possono fornire funzionalità e oggetti integrati diversi (e, naturalmente, alcuni non usano nemmeno la terminologia come "oggetti"!). Quindi le soluzioni che hanno un senso in una lingua potrebbero essere meno utili in un'altra (questo può anche applicarsi a versioni diverse della stessa lingua!).
Storicamente, gran parte della letteratura OOP (in particolare "modelli di progettazione") si è concentrata su Java, che è abbastanza diverso da Python. Ad esempio, le classi Java non sono oggetti, Java non aveva oggetti funzione fino a poco tempo fa, Java ha un rigoroso controllo del tipo (che incoraggia le interfacce e la sottoclasse) mentre Python incoraggia la tipizzazione duck, Java non ha oggetti modulo, numeri interi Java / galleggianti / etc. non sono oggetti, la meta-programmazione / introspezione in Java richiede "riflessione" e così via.
Non sto cercando di scegliere Java (come altro esempio, molta teoria OOP ruota attorno a Smalltalk, che è di nuovo molto diverso da Python), sto solo cercando di sottolineare che dobbiamo pensare molto attentamente al contesto e i vincoli in cui sono state sviluppate le soluzioni e se ciò corrisponde alla situazione in cui ci troviamo.
Nel tuo caso, un oggetto funzione sembra una buona scelta. Se ti stai chiedendo perché alcune linee guida di "best practice" non menzionino gli oggetti funzione come una possibile soluzione, potrebbe essere semplicemente perché quelle linee guida sono state scritte per le vecchie versioni di Java!