Я думаю, что ваша интуиция права.
Исторически вызываемые объекты (или то, что я иногда слышал как «функторы») использовались в мире ОО для имитации замыканий. В C ++ они часто незаменимы.
Однако у __call__
есть немало конкурентов в мире Python:
- Обычный именованный метод, поведение которого иногда намного проще вывести из имени. Можно преобразовать в связанный метод, который можно вызывать как функцию.
- Замыкание, полученное путем возврата функции, определенной во вложенном блоке.
- Лямбда, которая является ограниченным, но быстрым способом сделать закрытие.
- Генераторы и сопрограммы, чьи тела удерживают накопленное состояние так же, как и функтор.
Я бы сказал, что время использования __call__
- это когда вам не подходит один из вариантов выше. Проверьте следующие критерии, возможно:
- Ваш объект имеет состояние.
- Для вашего класса существует явное "первичное" поведение, которое глупо называть. Например. если вы пишете
run()
или doStuff()
или go()
или когда-либо популярное и постоянно избыточное doRun()
, у вас может быть кандидат.
- Ваш объект имеет состояние, которое превышает ожидаемое от функции генератора.
- Ваш объект оборачивает, эмулирует или абстрагирует концепцию функции.
- У вашего объекта есть другие вспомогательные методы, которые концептуально связаны с вашим основным поведением.
Один пример, который мне нравится, это объекты команд UI. Разработанный таким образом, чтобы их основной задачей было выполнение команд, но с дополнительными методами, например, для управления их отображением в качестве пункта меню, мне кажется, что это то, для чего вам все еще нужен вызываемый объект. *