Да, когда вы знаете, что имеете дело с объектами, вполне возможно (и во многих случаях желательно) использовать явный вызов метода. Однако иногда вы имеете дело с кодом, который ожидает вызываемые объекты - как правило, функции, но благодаря __call__
вам вы можете создавать более сложные объекты, с данными экземпляра и большим количеством методов для делегирования повторяющихся задач и т. Д., Которые все еще могут вызываться.
Кроме того, иногда вы используете как объекты для сложных задач (где имеет смысл написать выделенный класс), так и объекты для простых задач (которые уже существуют в функциях или легче записываются как функции). Чтобы иметь общий интерфейс, вы должны либо написать крошечные классы, обертывающие эти функции ожидаемым интерфейсом, либо оставить функции функций и сделать более сложные объекты вызываемыми. Давайте возьмем темы в качестве примера. Эти Thread
объекты из стандартного модуля libarythreading
хотят вызываемые в качестве 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__
что - то другое и передать связанный метод, но это делает код немного менее очевидно , создавая поток, и не добавляет никакой ценности.