Теперь, когда ясно, что такое метакласс, есть связанное с ним понятие, которое я постоянно использую, не зная, что оно на самом деле означает.
Я полагаю, что все когда-то допускали ошибку со скобками, что приводило к исключению "объект не вызывается". Более того, использование __init__ и __new__ заставляет задуматься, для чего этот чертов __call__ можно использовать.
Не могли бы вы дать мне несколько объяснений, включая примеры с волшебным методом ?
Переведено автоматически
Ответ 1
Вызываемый объект - это все, что может быть вызвано.
относится к типу, который имеет ненулевой член tp_call (c struct), который указывает на возможность вызова в противном случае (например, в функциях, методах и т.д.)
int PyCallable_Check(PyObject *x) { if (x == NULL) return0; if (PyInstance_Check(x)) { PyObject *call = PyObject_GetAttrString(x, "__call__"); if (call == NULL) { PyErr_Clear(); return0; } /* Could test recursively but don't, for fear of endless recursion if some joker sets self.__call__ = self */ Py_DECREF(call); return1; } else { return x->ob_type->tp_call != NULL; } }
В нем говорится:
Если объект является экземпляром некоторого класса, то он вызываем, если у него есть __call__ атрибут.
Иначе объект x можно вызывать, еслиx->ob_type->tp_call != NULL
ternaryfunc tp_call Необязательный указатель на функцию, которая реализует вызов объекта. Это значение должно быть NULL, если объект не вызывается. Сигнатура такая же, как для PyObject_Call() . Это поле наследуется подтипами.
Вы всегда можете использовать встроенную callable функцию, чтобы определить, является ли данный объект вызываемым или нет; или еще лучше просто вызвать его и перехватить TypeError позже. callable удалено в Python 3.0 и 3.1, используйте callable = lambda o: hasattr(o, '__call__') или isinstance(o, collections.Callable).
Пример упрощенной реализации кэша:
classCached: def__init__(self, function): self.function = function self.cache = {}
def__call__(self, *args): try: return self.cache[args] except KeyError: ret = self.cache[args] = self.function(*args) return ret
Использование:
@Cached defack(x, y): return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1)
Пример из стандартной библиотеки, файла site.py, определение встроенных exit() и quit() функций:
classQuitter(object): def__init__(self, name): self.name = name def__repr__(self): return'Use %s() or %s to exit' % (self.name, eof) def__call__(self, code=None): # Shells like IDLE catch the SystemExit, but listen when their # stdin wrapper is closed. try: sys.stdin.close() except: pass raise SystemExit(code) __builtin__.quit = Quitter('quit') __builtin__.exit = Quitter('exit')
Ответ 3
Вызываемый объект позволяет использовать функцию круглых скобок ( ) и в конечном итоге передавать некоторые параметры, точно так же, как функции.
Каждый раз, когда вы определяете функцию, python создает вызываемый объект. В примере вы могли бы определить функцию func следующими способами (это одно и то же):
Вы могли бы использовать этот метод вместо таких методов, как doit или run, я думаю, что просто obj() виднее, чем obj.doit()
Ответ 4
Позвольте мне объяснить в обратном порядке:
Учтите это...
foo()
... в качестве синтаксического сахара для:
foo.__call__()
Где foo может быть любой объект, который реагирует на __call__. Когда я говорю "любой объект", я имею в виду это: встроенные типы, ваши собственные классы и их экземпляры.
В случае встроенных типов, когда вы пишете:
int('10') unicode(10)
По сути, вы делаете:
int.__call__('10') unicode.__call__(10)
Вот почему у вас также нет foo = new int в Python: вы просто заставляете объект класса возвращать его экземпляр на __call__. Способ, которым Python решает это, на мой взгляд, очень элегантный.