Что такое "вызываемый" в Python?
Теперь, когда ясно, что такое метакласс, есть связанная концепция, которую я использую все время, не зная, что это на самом деле означает.
Я полагаю, что все однажды допустили ошибку с круглыми скобками, что привело к исключению "объект не может быть вызван". Более того, используя __init__
а также __new__
привести к удивлению, что это кровавое __call__
может быть использован для.
Не могли бы вы дать мне некоторые объяснения, в том числе примеры с магическим методом?
13 ответов
Вызываемым является все, что можно назвать.
Встроенный callable (PyCallable_Check в objects.c) проверяет, является ли аргумент одним из следующих:
- экземпляр класса с методом __call__ или
- имеет тип, который имеет ненулевой член tp_call (c struct), который указывает на возможность вызова в противном случае (например, в функциях, методах и т. д.)
Метод с именем __call__ есть ( согласно документации)
Вызывается, когда экземпляр вызывается как функция.
пример
class Foo:
def __call__(self):
print 'called'
foo_instance = Foo()
foo_instance() #this is calling the __call__ method
Из исходного кода Python object.c:
/* Test whether an object can be called */
int
PyCallable_Check(PyObject *x)
{
if (x == NULL)
return 0;
if (PyInstance_Check(x)) {
PyObject *call = PyObject_GetAttrString(x, "__call__");
if (call == NULL) {
PyErr_Clear();
return 0;
}
/* Could test recursively but don't, for fear of endless
recursion if some joker sets self.__call__ = self */
Py_DECREF(call);
return 1;
}
else {
return x->ob_type->tp_call != NULL;
}
}
Это говорит:
- Если объект является экземпляром некоторого класса, то он вызывается, если он имеет
__call__
приписывать. - Еще объект
x
вызывается,еслиx->ob_type->tp_call != NULL
Описаниеtp_call
поле:
ternaryfunc tp_call
Необязательный указатель на функцию, которая реализует вызов объекта. Это должно быть NULL, если объект не может быть вызван. Подпись такая же, как и для PyObject_Call(). Это поле наследуется подтипами.
Вы всегда можете использовать встроенный callable
функция для определения, является ли данный объект вызываемым или нет; или еще лучше просто позвони и поймай TypeError
потом. callable
удаляется в Python 3.0 и 3.1, используйтеcallable = lambda o: hasattr(o, '__call__')
или жеisinstance(o, collections.Callable)
,
Пример упрощенной реализации кэша:
class Cached:
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
def ack(x, y):
return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1)
Пример из стандартной библиотеки, файлsite.py
, определение встроенного exit()
а также quit()
функции:
class Quitter(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')
Вызываемый объект - это объект, который позволяет вам использовать круглые скобки () и в итоге передавать некоторые параметры, как функции.
Каждый раз, когда вы определяете функцию, python создает вызываемый объект. Например, вы можете определить функцию func следующим образом (это то же самое):
class a(object):
def __call__(self, *args):
print 'Hello'
func = a()
# or ...
def func(*args):
print 'Hello'
Вы можете использовать этот метод вместо методов типа doit или run, я думаю, что более просто увидеть obj(), чем obj.doit()
Позвольте мне объяснить в обратном направлении:
Учти это...
foo()
... как синтаксический сахар для:
foo.__call__()
куда foo
может быть любым объектом, который реагирует на __call__
, Когда я говорю любой объект, я имею в виду это: встроенные типы, ваши собственные классы и их экземпляры.
В случае встроенных типов, когда вы пишете:
int('10')
unicode(10)
Вы по существу делаете:
int.__call__('10')
unicode.__call__(10)
Вот почему у вас нет foo = new int
в Python: вы просто заставляете объект класса возвращать его экземпляр на __call__
, Способ, которым Python решает эту проблему, на мой взгляд, очень элегантен.
__call__
делает любой объект вызываемым как функцию.
Этот пример выведет 8:
class Adder(object):
def __init__(self, val):
self.val = val
def __call__(self, val):
return self.val + val
func = Adder(5)
print func(3)
Callable - это объект, который имеет __call__
метод. Это означает, что вы можете подделывать вызываемые функции или делать изящные вещи, такие как Partial Function Application, где вы берете функцию и добавляете что-то, что улучшает ее или заполняет некоторые параметры, возвращая что-то, что может быть вызвано по очереди (это называется каррированием в кругах функционального программирования).).
В некоторых типографских ошибках интерпретатор пытается вызвать то, что вы не хотели, например, например, строку. Это может привести к ошибкам, когда интерпретатор пытается выполнить не вызываемое приложение. Вы можете увидеть это в интерпретаторе python, выполнив что-то вроде стенограммы ниже.
[nigel@k9 ~]$ python
Python 2.5 (r25:51908, Nov 6 2007, 15:55:44)
[GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'aaa'() # <== Here we attempt to call a string.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
>>>
Проще говоря, "вызываемый" - это то, что можно вызвать как метод. Встроенная функция "callable()" сообщит вам, кажется ли что-то вызываемым, как и проверка свойства вызова. Функции могут быть вызваны как классы, экземпляры классов могут быть вызваны. Подробнее об этом здесь и здесь.
В Python вызываемый объект - это объект, тип которого имеет __call__
метод:
>>> class Foo:
... pass
...
>>> class Bar(object):
... pass
...
>>> type(Foo).__call__(Foo)
<__main__.Foo instance at 0x711440>
>>> type(Bar).__call__(Bar)
<__main__.Bar object at 0x712110>
>>> def foo(bar):
... return bar
...
>>> type(foo).__call__(foo, 42)
42
Так просто:)
Это, конечно, может быть перегружено:
>>> class Foo(object):
... def __call__(self):
... return 42
...
>>> f = Foo()
>>> f()
42
Проверка функции или метода класса является вызываемой или нет, это означает, что мы можем вызвать эту функцию.
Class A:
def __init__(self,val):
self.val = val
def bar(self):
print "bar"
obj = A()
callable(obj.bar)
True
callable(obj.__init___)
False
def foo(): return "s"
callable(foo)
True
callable(foo())
False
Это то, что вы можете поставить "(аргументы)" после и ожидать, что это сработает. Вызываемый - это обычно метод или класс. Методы вызываются, классы создаются.
Callable - это тип или класс "встроенной функции или метода" свызовом метода.
>>> type(callable)
<class 'builtin_function_or_method'>
>>>
Пример:print является вызываемым объектом. Со встроенной функцией __call__ Когда вы вызываете функцию печати, Python создает объект типа print и вызывает его метод __call__, передавая параметры, если таковые имеются.
>>> type(print)
<class 'builtin_function_or_method'>
>>> print.__call__(10)
10
>>> print(10)
10
>>>
Спасибо. С уважением, Марис
Вызовы реализуют __call__
специальный метод, поэтому любой объект с таким методом может быть вызван.
Класс, функция, метод и объект, который имеет callable .
Вы можете проверить, можно ли вызывать с помощью callable() , который возвращаетTrue
если вызывается и возвращает, если не вызывается, как показано ниже:
class Class1:
def __call__(self):
print("__call__")
class Class2:
pass
def func():
pass
print(callable(Class1)) # Class1
print(callable(Class2)) # Class2
print(callable(Class1())) # Class1 object
print(callable(Class2())) # Class2 object
print(callable(func)) # func
Тогда только
Class2
объект , не имеющий__call__()
не вызывается, как показано ниже:
True # Class1
True # Class2
True # Class1 object
False # Class2 object
True # func
Кроме того, все нижеперечисленные функции нельзя вызывать, возвращаяFalse
как показано ниже:
print(callable("Hello")) # "str" type
print(callable(100)) # "int" type
print(callable(100.23)) # "float" type
print(callable(100 + 2j)) # "complex" type
print(callable(True)) # "bool" type
print(callable(None)) # "NoneType"
print(callable([])) # "list" type
print(callable(())) # "tuple" type
print(callable({})) # "dict" type
print(callable({""})) # "set" type
Выход:
False # "str" type
False # "int" type
False # "float" type
False # "complex" type
False # "bool" type
False # "NoneType"
False # "list" type
False # "tuple" type
False # "dict" type
False # "set" type