Що таке "дзвінок"?


310

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

Я припускаю, що кожен раз помилився з дужками, в результаті чого виняток "об'єкт не можна називати". Більше того, використовуючи __init__та __new__приводячи до думки, для чого цей кривавий __call__можна використовувати.

Чи можете ви дати мені кілька пояснень, зокрема приклади з магічним методом?


Відповіді:


308

Дзвінки - це все, що можна назвати.

Вбудований відкликані (PyCallable_Check в objects.c) перевірки , якщо аргумент є:

  • екземпляр класу __call__методом або
  • - це тип, який має ненульовий член tp_call (c struk ), який вказує на можливість виклику інакше (наприклад, у функціях, методах тощо)

Метод названий __call__( згідно з документацією )

Викликається, коли екземпляр '' викликається '' як функція

Приклад

class Foo:
  def __call__(self):
    print 'called'

foo_instance = Foo()
foo_instance() #this is calling the __call__ method

6
Зауважте, що вбудований дзвінок
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. ".
Тадек

Здається, в 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називається iff 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 Себастьян, також складати більше прикладів, які ви копіюєте та вставляєте десь із інших місць, які не є мінімальними, не допомагає.
Флоріан Бьош

20
@JF Себастьян: Більше таких життєвих прикладів краще. Я можу показати вам життєвий код, який би змусив вас плакати як приклад. Прості приклади теж працюють, і вони краще ілюструють щось, тому що вони не відволікають.
Флоріан Бьош

5
Ви пояснюєте, що називається, але ви навели приклад, як використовувати об'єкти, що викликаються, щоб визначити декоратор. Я знаю, що це типове використання дзвінка, але це може збити з пантелику читачів, які просто хочуть знати, що можна викликати та як використовувати дзвінок . Я вважаю за краще відповідь @Florian Bösch.
KFL

2
@Kay: мені також подобається відповідь @Florian Bösch (у її теперішній формі). btw, декоратор - не типове використання "дзвінка". Найбільш типові «є» викликаються об'єктами функції / методами , такими , як def f(): ...і об'єктів класу , таким , як class C: ...наприклад, f, ''.strip, lenі Cвсе можуть бути відкликані. Випадки, які мають __call__()метод у своєму класі, відносно рідкісні.
jfs

37

Викликається об'єкт дозволяє використовувати круглі дужки () і в підсумку передавати деякі параметри, як і функції.

Кожен раз, коли ви визначаєте функцію, python створює об'єкт, що викликається. Наприклад, ви можете визначити функцію функції цими способами (це те саме):

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'). Дандерів завжди викликають у своєму класі, а не через екземпляр. І вони також ніколи не проходять через метаклас. У більшості випадків це просто нитка, але це має значення і іноді.
Божевільний фізик

11

Callable - це об'єкт, який має __call__метод. Це означає, що ви можете підробляти функції дзвінка або робити акуратні речі на зразок додатка для часткової функції, коли ви берете функцію і додаєте щось, що її покращує, або заповнює деякі параметри, повертаючи щось, що можна викликати по черзі (відоме як Currying у колах функціонального програмування ).

Певні друкарські помилки перекладач намагатиметься викликати те, що ви не мали наміру, наприклад (наприклад, рядок). Це може призвести до помилок, коли інтерпретатор намагається виконати програму, що не викликається. Ви можете бачити, що це відбувається в інтерпретаторі 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__ Коли ви викликаєте функцію друку , Python створює об’єкт типу друку та викликає його метод __call__, передаючи параметри, якщо такі є.

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

Дякую. З повагою, Маріс


1
Деяка інформація тут прямо неправильна. Наприклад, "Коли ви викликаєте printфункцію, Python створює об'єкт друку типу і викликає його метод __call__". Python не створює об'єкт друку. Це просто називає щось рівнозначне type(print).__call__(print, *args, **kwargs). І перше речення не має великого сенсу. Здається, ви плутаєте об'єкт, що викликається, і функцію "дзвонить".
Божевільний фізик
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.