Да, когда вы знаете, что имеете дело с объектами, вполне возможно (и во многих случаях желательно) использовать явный вызов метода.Однако иногда вы имеете дело с кодом, который ожидает вызываемые объекты - как правило, функции, но благодаря __call__
вы можете создавать более сложные объекты с данными экземпляра и большим количеством методов для делегирования повторяющихся задач и т. Д., Которые все еще могут вызываться.
Кроме того, иногда вы используете как объекты для сложных задач (где имеет смысл написать выделенный класс), так и объекты для простых задач (которые уже существуют в функциях или легче записываются как функции).Чтобы иметь общий интерфейс, вы должны либо написать крошечные классы, обертывающие эти функции ожидаемым интерфейсом, либо оставить функции функций и сделать более сложные объекты вызываемыми.Давайте возьмем темы в качестве примера.Объекты Thread
из стандартного модуля libary threading
хотят вызвать как аргумент target
(т. Е. Как действие, которое должно быть выполнено в новом потоке).С вызываемым объектом вы не ограничены функциями, вы также можете передавать другие объекты, например, относительно сложного работника, который получает задачи для выполнения из других потоков и выполняет их последовательно:
class Worker(object):
def __init__(self, *args, **kwargs):
self.queue = queue.Queue()
self.args = args
self.kwargs = kwargs
def add_task(self, task):
self.queue.put(task)
def __call__(self):
while True:
next_action = self.queue.get()
success = next_action(*self.args, **self.kwargs)
if not success:
self.add_task(next_action)
Этопросто пример из головы, но я думаю, что это уже достаточно сложно, чтобы оправдать класс.Делать это только с функциями сложно, по крайней мере, это требует возврата двух функций, и это постепенно становится сложным.Один может переименовать __call__
во что-то другое и передать связанный метод, но это делает код, создающий поток, немного менее очевидным и не добавляет никакого значения.