Ми можемо розглядати OOP як моделювання поведінки системи. Зауважте, що система не повинна існувати у "реальному світі", хоча метафори реального світу іноді можуть бути корисними (наприклад, "трубопроводи", "фабрики" тощо).
Якщо наша бажана система є надто складною для моделювання всіх відразу, ми можемо розбити її на більш дрібні шматки та моделювати ті ("проблемний домен"), що може включати подальше руйнування, і так далі, поки ми не знайдемо деталі, поведінка яких збігається (більш-менш) об'єкта якогось вбудованого мовного об'єкта, наприклад, числа, рядка, списку тощо.
Після того, як у нас з’являться ці прості фрагменти, ми можемо їх об'єднати, щоб описати поведінку більших шматочків, які ми можемо поєднати разом у ще більші шматки, і так далі, поки не зможемо описати всі компоненти домену, необхідні для цілого система.
Саме ця фаза "поєднання разом" ми можемо написати кілька класів. Ми пишемо класи, коли немає існуючого об'єкта, який веде себе так, як ми хочемо. Наприклад, наш домен може містити "foos", колекції foos під назвою "bars" та колекції барів під назвою "bazs". Ми можемо помітити, що foos досить простий для моделювання струн, тому ми це робимо. Ми виявляємо, що бари вимагають, щоб їх вміст підкорявся якомусь певному обмеженню, яке не відповідає нічого, що надає Python, і в такому випадку ми можемо написати новий клас для забезпечення цього обмеження. Можливо, у баз немає таких особливостей, тому ми можемо просто представити їх списком.
Зауважте, що ми могли б написати новий клас для кожного з цих компонентів (футів, барів і баз), але нам цього не потрібно, якщо вже є щось з правильною поведінкою. Зокрема, щоб клас був корисним, він повинен щось «надати» (дані, методи, константи, підкласи тощо), тому навіть якщо у нас є багато шарів спеціальних класів, ми зрештою повинні використовувати якусь вбудовану функцію; Наприклад, якщо ми написали новий клас для foos, він, ймовірно, просто містив би рядок, то чому б не забути foo-клас і щоб бар-клас містив ці рядки замість цього? Майте на увазі, що класи - це також вбудований об’єкт, вони просто особливо гнучкі.
Отримавши нашу доменну модель, ми можемо взяти деякі конкретні екземпляри цих фрагментів і впорядкувати їх на "моделювання" конкретної системи, яку ми хочемо моделювати (наприклад, "система машинного навчання для ...").
Після того, як у нас є таке моделювання, ми зможемо запустити його та пристосуємось до престо, ми маємо працюючу (моделювання а) машинної системи навчання для ... (або будь-якого іншого, що ми моделювали).
Тепер у вашій конкретній ситуації ви намагаєтеся моделювати поведінку компонента "екстрактор функцій". Питання в тому, чи є вбудовані об’єкти, які ведуть себе як "екстрактор функцій", чи вам потрібно буде розбити його на більш прості речі? Схоже, екстрактори функціонують дуже схоже на об'єкти функцій, тому я думаю, вам було б добре використовувати їх як вашу модель.
Одне, що слід пам’ятати, вивчаючи подібні поняття, - це те, що різні мови можуть надавати різні вбудовані функції та об’єкти (і, звичайно, деякі навіть не використовують термінологію, як «об’єкти»!). Отже, рішення, що мають сенс для однієї мови, можуть бути менш корисними для іншої (це може стосуватися навіть різних версій однієї мови!).
Історично багато літератури OOP (особливо "дизайнерські зразки") зосереджувались на Java, що сильно відрізняється від Python. Наприклад, класи Java не є об’єктами, у Java не було функціональних об'єктів ще зовсім недавно, у Java є сувора перевірка типів (що заохочує інтерфейси та підкласифікацію), в той час як Python заохочує введення качок, у Java немає об'єктів модулів, цілі Java / плаває / тощо. не є об'єктами, метапрограмування / інтроспекція на Java вимагає "рефлексії" тощо.
Я не намагаюся вибирати Java (як інший приклад, багато теорії OOP обертається навколо Smalltalk, який знову дуже відрізняється від Python), я просто намагаюся зазначити, що ми повинні дуже ретельно думати про контекст і обмеження, в яких розроблені рішення та чи відповідає це ситуації, в якій ми знаходимося.
У вашому випадку об’єкт функції здається хорошим вибором. Якщо вам цікаво, чому в деякому керівництві "найкраща практика" не згадуються функціональні об'єкти як можливе рішення, це може бути просто тому, що ці вказівки були написані для старих версій Java!