Подтвердить что ты не робот

Когда используется __call__ хорошая идея?

Каковы мнения людей об использовании __call__. Я очень редко видел, что он используется, но я считаю, что это очень удобный инструмент для использования, когда вы знаете, что класс будет использоваться для какого-либо поведения по умолчанию.

4b9b3361

Ответ 1

Я думаю, что ваша интуиция в порядке.

Исторически, вызываемые объекты (или то, что я иногда слышал, называемые "функторы" ) были использованы в мире ОО для имитации замыканий. В С++ они часто незаменимы.

Однако, __call__ имеет довольно много конкуренции в мире Python:

  • Регулярный именованный метод, поведение которого иногда может быть намного легче выведено из имени. Можно преобразовать в метод bound, который можно вызвать как функцию.
  • Закрытие, полученное возвратом функции, определенной во вложенном блоке.
  • Лямбда, которая является ограниченным, но быстрым способом сделать закрытие.
  • Генераторы и сопрограммы, тела которых имеют накопленное состояние, подобно функтору.

Я бы сказал, что время использовать __call__ - это то, когда вам не лучше обслуживать один из вышеперечисленных вариантов. Проверьте следующие критерии:

  • У вашего объекта есть состояние.
  • Для вашего класса существует явное "первичное" поведение, которое глупо назвать. Например. если вы обнаружите, что пишете run() или doStuff() или go() или когда-либо популярный и постоянно избыточный doRun(), у вас может быть кандидат.
  • В вашем объекте есть состояние, превышающее ожидаемое от генераторной функции.
  • Ваш объект обертывает, эмулирует или абстрагирует концепцию функции.
  • В вашем объекте есть другие вспомогательные методы, которые концептуально принадлежат вашему основному поведению.

Один пример, который мне нравится, это объекты команды UI. Разработанный таким образом, что их основной задачей является выполнение команды, но с дополнительными методами для управления их отображением в качестве элемента меню, например, мне кажется, что это то, что вы все еще хотите для вызываемого объекта.

Ответ 2

Используйте его, если вам нужно, чтобы ваши объекты были вызываемыми, что он там для

Я не уверен, что вы подразумеваете по умолчанию поведение

Одно из мест, которое я нашел особенно полезным, - это использование обертки или somesuch, где объект называется глубоко внутри некоторой фреймворка/библиотеки.

Ответ 3

В более общем плане, Python имеет много методов с двойным подчеркиванием. Они есть не по какой-то причине: это Python способ перегрузки операторов. Например, если вы хотите новый класс, в котором добавление, я не знаю, печатает "foo", вы определяете методы __add__ и __radd__. В этом нет ничего хорошего или плохого, нежели ничего хорошего или плохого в использовании циклов for.

Фактически, использование __call__ часто является более питоническим подходом, поскольку оно способствует ясности кода. Вы можете заменить MyCalculator.calculateValues( foo ) на MyCalculator( foo ), скажем.

Ответ 4

Его обычно используют, когда класс используется как функция с каким-то контекстом экземпляра, например, некоторым DecoratorClass, который будет использоваться как @DecoratorClass('some param'), поэтому "некоторый параметр" будет храниться в пространстве имен экземпляров, а затем экземпляр будет вызываться как фактический декоратор.

Не очень полезно, когда ваш класс предоставляет несколько разных методов, так как обычно неясно, что бы сделал вызов, а явный лучше, чем неявный в этих случаях.