Что такое «вызываемый»?


312

Теперь, когда ясно, что такое метакласс , есть связанная концепция, которую я использую все время, не зная, что это на самом деле означает.

Я полагаю, что все однажды допустили ошибку с круглыми скобками, что привело к исключению «объект не может быть вызван». Более того, использование __init__и __new__привести к удивлению, для чего __call__может быть использован этот кровавый .

Не могли бы вы дать мне некоторые объяснения, в том числе примеры с магическим методом?


Ответы:


310

Вызываемым является все, что можно назвать.

Встроенный отозваны (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

6
Обратите внимание, что встроенный вызываемый элемент убирается в Python 3.0 в пользу проверки вызова
Eli Courtwright

13
@Eli: Хм, это звучит как очень плохой ход. callableна самом деле говорит вам, если что-то вызывается или нет, в то время как проверка для __call__вас ничего не говорит; Если объект oпредоставляет __getattribute__или __getattr__, hasattr(o, '__call__')может вернуть True, он все oравно не будет вызываться из-за пропуска Python __getattribute__и __getattr__для вызовов. Таким образом, единственный реальный способ проверить, является ли что-то вызываемым, - это EAFP.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

49
@Longpoke: Просто для справки, смотрите документацию по callable()Python 3.x : « Эта функция была сначала удалена в Python 3.0, а затем возвращена в Python 3.2. ».
Tadeck

Кажется, в Python 3.8 tp_callпроверяется только наличие . Смотрите реализацию PyCallable_Check , это 3 строки.
Мишель Пикколини

84

Из исходного кода 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;
    }
}

Это говорит:

  1. Если объект является экземпляром некоторого класса, то он вызывается, если у него есть __call__атрибут.
  2. Еще объект 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')

10
Я нахожу пример метода вызова очень ошибочным, потому что он смешивает его с рецептом кеширования и декораторами, которые ничего не добавляют к пониманию вызова
Флориан Бёш

3
JF Sebastian, также куча примеров, которые вы копируете и вставляете из другого места, которые не являются минимальными, не помогает.
Флориан Бош

20
@JF Себастьян: Это BS, чем больше примеров из жизни, тем лучше. Я мог бы показать вам жизненный код, который заставил бы вас плакать в качестве примера. Работают и простые примеры, и они лучше иллюстрируют, потому что не отвлекают.
Флориан Бёш

5
Вы объясняете, что вызывается, но вы привели пример, как использовать вызываемые объекты для определения декоратора. Я знаю, что это типичное использование callable, но это может сбить с толку читателей, которые просто хотят знать, что вызывается и как использовать callable . Я бы предпочел ответ @Florian Bösch.
KFL

2
@Kay: Мне также нравится ответ @Florian Bösch (в его нынешнем виде). Кстати, декоратор не является типичным использованием "вызываемого". Наиболее типичные «являются» вызываемыми объектами функции / методами , такими , как def f(): ...и объектов класса , таким , как class C: ...например, f, ''.strip, lenи Cвсе могут быть отозваны. Экземпляры, у которых есть __call__()метод в своем классе, относительно редки.
JFS

37

Вызываемый объект - это объект, который позволяет вам использовать круглые скобки () и в конечном итоге передавать некоторые параметры, как функции.

Каждый раз, когда вы определяете функцию, python создает вызываемый объект. Например, вы можете определить функцию func следующим образом (это то же самое):

class a(object):
    def __call__(self, *args):
        print 'Hello'

func = a()

# or ... 
def func(*args):
    print 'Hello'

Вы можете использовать этот метод вместо методов типа doit или run , я думаю, что более просто увидеть obj (), чем obj.doit ()


37

Позвольте мне объяснить в обратном направлении:

Учти это...

foo()

... как синтаксический сахар для:

foo.__call__()

Где fooможет быть любой объект, который отвечает __call__. Когда я говорю любой объект, я имею в виду это: встроенные типы, ваши собственные классы и их экземпляры.

В случае встроенных типов, когда вы пишете:

int('10')
unicode(10)

Вы по существу делаете:

int.__call__('10')
unicode.__call__(10)

Вот почему у вас нет foo = new intв Python: вы просто заставляете объект класса возвращать его экземпляр __call__. Способ, которым Python решает эту проблему, на мой взгляд, очень элегантен.


Вы по сути дела type(int).__call__(int, '10')и type(unicode).__call__(unicode, '10'). Dunders всегда вызывается в их классе, а не через экземпляр. И они никогда не проходят через метакласс. В большинстве случаев это просто придурок, но иногда это важно.
Безумный физик

11

Callable - это объект, у которого есть __call__метод. Это означает, что вы можете подделывать вызываемые функции или делать изящные вещи, такие как Partial Function Application, где вы берете функцию и добавляете что-то, что улучшает ее или заполняет некоторые параметры, возвращая что-то, что может быть вызвано по очереди (так называемое Curry в кругах функционального программирования). ).

Некоторые типографские ошибки приводят к тому, что интерпретатор пытается вызвать то, что вы не хотели, например (например) строку. Это может привести к ошибкам, когда интерпретатор пытается выполнить не вызываемое приложение. Вы можете увидеть это в интерпретаторе 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
>>> 

9

__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)

7

Проще говоря, «вызываемый» - это то, что можно вызвать как метод. Встроенная функция «callable ()» сообщит вам, кажется ли что-то вызываемым, так же как и проверка свойства вызова . Функции могут вызываться так же, как и классы, экземпляры классов могут быть вызваны. Подробнее об этом здесь и здесь .


5

В 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

3

Проверка функции или метода класса является вызываемой или нет, это означает, что мы можем вызвать эту функцию.

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

1
Вы уверены, callable(obj.__init___)что нет лишнего подчеркивания (как в AttributeError)? Если это не так, вы уверены, что ответ не Trueдля этого?
Безумный физик

2

Это то, что вы можете поставить "(args)" после и ожидать, что это сработает. Вызываемый - это обычно метод или класс. Методы вызываются, классы создаются.


2

callables реализуют __call__специальный метод, поэтому любой объект с таким методом может быть вызван.


Экземпляр, который вы определяете __call__, не будет вызываться, если класс не определяет такой метод.
Безумный физик

2

Callable - это тип или класс «встроенной функции или метода» с вызовом метода.

>>> type(callable)
<class 'builtin_function_or_method'>
>>>

Пример: print является вызываемым объектом. Со встроенной функцией __call__ Когда вы вызываете функцию print , Python создает объект типа print и вызывает его метод __call__, передавая параметры, если они есть.

>>> type(print)
<class 'builtin_function_or_method'>
>>> print.__call__(10)
10
>>> print(10)
10
>>>

Спасибо. С уважением, Марис


1
Некоторая информация здесь совершенно неправильная. Например, «Когда вы вызываете printфункцию, Python создает объект типа print и вызывает его метод __call__». Python не создает объект печати. Это просто вызывает что-то эквивалентное type(print).__call__(print, *args, **kwargs). И первое предложение не имеет особого смысла. Вы, кажется, путаете вызываемый объект и «вызываете» функцию.
Безумный физик
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.