Co to jest „na żądanie”?


310

Teraz, gdy jest jasne, co to jest metaklasa , istnieje powiązana koncepcja, z której korzystam cały czas, nie wiedząc, co to naprawdę oznacza.

Przypuszczam, że wszyscy popełnili kiedyś błąd w nawiasie, co spowodowało wyjątek „obiekt nie jest wywoływalny”. Co więcej, używanie __init__i __new__prowadzi do zastanawiania się, do czego ten cholerny __call__można wykorzystać.

Czy możesz podać mi wyjaśnienia, w tym przykłady z magiczną metodą?


Odpowiedzi:


308

Odwołanie to wszystko, co można nazwać.

Wbudowaną wymagalne (PyCallable_Check w objects.c) sprawdza, czy argument jest:

  • instancja klasy z __call__metodą lub
  • jest typu, który ma inny niż tull element tp_call (c struct), który wskazuje inaczej możliwość wywołania (np. w funkcjach, metodach itp.)

Nazwana metoda __call__to ( zgodnie z dokumentacją )

Wywoływany, gdy instancja jest wywoływana jako funkcja

Przykład

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

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

6
Zauważ, że wbudowane wywołanie
Eli Courtwright

13
@Eli: Hmm, to brzmi jak bardzo zły ruch. callablew rzeczywistości mówi ci, czy coś można wywołać, czy nie, podczas gdy sprawdzanie __call__, nic ci nie mówi; Jeśli obiekt oudostępnia __getattribute__lub __getattr__, hasattr(o, '__call__')może powrócić prawda, ale onie będą jeszcze wymagalne, ponieważ pomija Python __getattribute__i __getattr__do rozmów. Jedynym realnym sposobem na sprawdzenie, czy coś jest na żądanie, jest więc EAFP.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

49
@ Longpoke: Dla przypomnienia zapoznaj się z dokumentacją callable()w Pythonie 3.x : „ Ta funkcja została najpierw usunięta w Pythonie 3.0, a następnie przywrócona w Pythonie 3.2. ”.
Tadeck

Wydaje się, że w Pythonie 3.8 tp_callsprawdzana jest tylko obecność . Zobacz realizację PyCallable_Check , to 3 linie.
Michele Piccolini

84

Ze źródeł 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;
    }
}

To mówi:

  1. Jeśli obiekt jest instancją jakiejś klasy, można go wywołać, jeśli ma __call__atrybut.
  2. W przeciwnym razie obiekt xjest wywoływalny iff x->ob_type->tp_call != NULL

Opis tp_callpola :

ternaryfunc tp_callOpcjonalny wskaźnik do funkcji, która implementuje wywołanie obiektu. Powinien mieć wartość NULL, jeśli obiekt nie jest wywoływalny. Podpis jest taki sam, jak w przypadku PyObject_Call (). To pole jest dziedziczone przez podtypy.

Zawsze możesz użyć wbudowanej callablefunkcji, aby ustalić, czy dany obiekt można wywołać, czy nie; lub jeszcze lepiej po prostu zadzwoń i złap TypeErrorpóźniej. callablejest usunięty w Python 3.0 i 3.1, użyj callable = lambda o: hasattr(o, '__call__')lub isinstance(o, collections.Callable).

Przykład, uproszczona implementacja pamięci podręcznej:

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    

Stosowanie:

@Cached
def ack(x, y):
    return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1) 

Przykład ze standardowej biblioteki, pliku site.py, definicji wbudowanej exit()i quit()funkcji:

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
Uważam, że metoda wywołania jest bardzo myląca, ponieważ łączy ją z przepisem na buforowanie i dekoratorami, co nie wnosi nic do zrozumienia połączenia
Florian Bösch

3
JF Sebastian, również gromadzenie większej liczby przykładów, które skopiowałeś i wkleiłeś z innego miejsca, które nie są minimalne, nie pomaga.
Florian Bösch,

20
@JF Sebastian: To BS, że więcej przykładów podobnych do życia jest lepszych. Mógłbym ci pokazać kod, który sprawi, że będziesz płakać jako przykład. Proste przykłady też działają i lepiej je ilustrują, ponieważ nie rozpraszają uwagi.
Florian Bösch,

5
Wyjaśniasz, co można wywołać, ale podałeś przykład, w jaki sposób można użyć obiektów, które można wywołać, do zdefiniowania dekoratora. Wiem, że jest to typowe użycie wywoływania, ale może to dezorientować czytelników, którzy chcą wiedzieć, co jest wywoływane i jak korzystać z wywoływania . Wolałbym odpowiedź @Florian Bösch.
KFL

2
@Kay: Podoba mi się również odpowiedź @Florian Bösch (w obecnej formie). przy okazji dekorator nie jest typowym zastosowaniem „na żądanie”. Najbardziej typowym „callables” są funkcje / metody, takie jak def f(): ..., a klasa obiektów, takich jak class C: ...np f, ''.strip, len, i Cwszyscy są wymagalne. Wystąpienia, które mają __call__()metodę w swojej klasie, są stosunkowo rzadkie.
jfs

37

Callable to obiekt, który pozwala na użycie okrągłego nawiasu () i ostatecznie przekazanie niektórych parametrów, podobnie jak funkcji.

Za każdym razem, gdy definiujesz funkcję, python tworzy obiekt na żądanie. Na przykład możesz zdefiniować funkcję func na następujące sposoby (to samo):

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

func = a()

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

Możesz użyć tej metody zamiast metod takich jak doit lub run , myślę, że po prostu wyraźniej jest zobaczyć obj () niż obj.doit ()


37

Pozwól mi wyjaśnić wstecz:

Rozważ to...

foo()

... jako cukier syntaktyczny dla:

foo.__call__()

Gdzie foomoże być dowolny obiekt, który reaguje __call__. Kiedy mówię dowolny obiekt, mam na myśli: typy wbudowane, własne klasy i ich instancje.

W przypadku typów wbudowanych podczas pisania:

int('10')
unicode(10)

Zasadniczo wykonujesz:

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

Dlatego też nie masz foo = new intw Pythonie: po prostu sprawiasz, że obiekt klasy zwraca jego instancję __call__. Sposób, w jaki Python rozwiązuje ten problem, jest moim zdaniem bardzo elegancki.


Zasadniczo robisz type(int).__call__(int, '10')i type(unicode).__call__(unicode, '10'). Dundery są zawsze wywoływane w swojej klasie, a nie przez instancję. I nigdy też nie przechodzą przez metaklasę. W większości przypadków to tylko drobiazg, ale czasem ma to znaczenie.
Mad Physicist,

11

Callable to obiekt posiadający tę __call__metodę. Oznacza to, że możesz sfałszować wywoływane funkcje lub robić porządne rzeczy, takie jak Aplikacja Częściowa Funkcja, w której bierzesz funkcję i dodajesz coś, co ją ulepsza lub uzupełnia niektóre parametry, zwracając coś, co można wywołać z kolei (znane jako Currying w funkcjonalnych kręgach programowania ).

Niektóre błędy typograficzne spowodują, że interpreter będzie próbował wywołać coś, czego nie zamierzałeś, na przykład (na przykład) ciąg znaków. Może to powodować błędy, gdy interpreter próbuje uruchomić aplikację, której nie można wywołać. Możesz zobaczyć, jak to się dzieje w interpreterie python, wykonując coś w rodzaju transkrypcji poniżej.

[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__ sprawia, że ​​dowolny obiekt może być wywoływalny jako funkcja.

Ten przykład wyświetli 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

Po prostu „wywoływalny” to coś, co można nazwać metodą. Wbudowana funkcja „callable ()” powie ci, czy coś wydaje się być wywoływalne, podobnie jak sprawdzenie właściwości call . Funkcje są wywoływalne, podobnie jak klasy, instancje klas mogą być wywoływalne. Zobacz więcej na ten temat tutaj i tutaj .


5

W Pythonie wywoływalny jest obiekt, którego typ ma __call__metodę:

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

Tak proste jak to :)

To oczywiście może być przeciążone:

>>> class Foo(object):
...  def __call__(self):
...   return 42
... 
>>> f = Foo()
>>> f()
42

3

Sprawdzanie funkcji lub metody klasy jest możliwe do wywołania, czy nie, oznacza to, że możemy wywołać tę funkcję.

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
Czy na pewno callable(obj.__init___)nie ma dodatkowego podkreślenia (jak w AttributeError)? Jeśli nie, czy jesteś pewien, że odpowiedź nie jest na to pytanie True?
Mad Physicist,

2

Jest to coś, po czym możesz umieścić „(argumenty)” i oczekiwać, że zadziała. Wywołanie to zazwyczaj metoda lub klasa. Wywoływane są metody, tworzone są klasy.


2

callables implementuje __call__specjalną metodę, aby każdy obiekt z taką metodą był możliwy do wywołania.


Instancja, w której zdefiniujesz __call__, nie będzie możliwa do wywołania, jeśli klasa nie zdefiniuje takiej metody.
Mad Physicist,

2

Callable to typ lub klasa „funkcji wbudowanej lub metody” z wywołaniem metody

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

Przykład: print to obiekt na żądanie. Za pomocą wbudowanej funkcji __call__ Po wywołaniu funkcji print Python tworzy obiekt typu print i wywołuje metodę __call__ przekazując parametry, jeśli takie istnieją.

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

Dziękuję Ci. Pozdrawiam, Maris


1
Niektóre informacje tutaj są po prostu błędne. Np. „Gdy wywołujesz printfunkcję, Python tworzy obiekt typu print i wywołuje swoją metodę __call__”. Python nie tworzy obiektu drukowania. To po prostu nazywa coś równoważnego type(print).__call__(print, *args, **kwargs). A pierwsze zdanie nie ma większego sensu. Wygląda na to, że mylisz obiekt, który można wywołać, i „wywołuje” funkcję.
Mad Physicist,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.