¿Qué es un "invocable"?


312

Ahora que está claro qué es una metaclase , hay un concepto asociado que uso todo el tiempo sin saber lo que realmente significa.

Supongo que todos cometieron un error con paréntesis, lo que resultó en una excepción de "objeto no invocable". Además, usar __init__y __new__conducir a preguntarse para qué __call__se puede usar este sangriento .

¿Podría darme algunas explicaciones, incluidos ejemplos con el método mágico?


Respuestas:


310

Un invocable es cualquier cosa que se pueda llamar.

El built-in exigible (PyCallable_Check en objects.c) comprueba si el argumento es ya sea:

  • una instancia de una clase con un __call__método o
  • es de un tipo que tiene un miembro tp_call (c struct) no nulo que indica la posibilidad de invocabilidad de otro modo (como en funciones, métodos, etc.)

El método nombrado __call__es (de acuerdo con la documentación )

Se llama cuando la instancia se '' llama '' como una función

Ejemplo

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

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

66
Tenga en cuenta que el llamado invocable incorporado se está eliminando en Python 3.0 a favor de verificar la llamada
Eli Courtwright,

13
@Eli: Hmm, eso suena como un movimiento muy malo. callableen realidad le dice si algo es invocable o no, mientras que la verificación __call__no le dice nada; Si un objeto oproporciona __getattribute__o __getattr__, hasattr(o, '__call__')puede devolver True, oaún no será invocable porque Python omite __getattribute__y __getattr__para las llamadas. Por lo tanto, la única forma real de verificar si algo se puede llamar es EAFP.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

49
@Longpoke: solo para el registro, consulte la documentación callable()en Python 3.x : " Esta función se eliminó primero en Python 3.0 y luego se recuperó en Python 3.2 ".
Tadeck

Parece que en Python 3.8 solo tp_callse verifica la presencia de . Vea la implementación de PyCallable_Check , son 3 líneas.
Michele Piccolini

84

De las fuentes 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;
    }
}

Dice:

  1. Si un objeto es una instancia de alguna clase, es invocable si tiene __call__atributo.
  2. De lo contrario, el objeto xes invocable si x->ob_type->tp_call != NULL

Descipción de tp_callcampo :

ternaryfunc tp_callUn puntero opcional a una función que implementa la llamada al objeto. Esto debería ser NULL si el objeto no es invocable. La firma es la misma que para PyObject_Call (). Este campo es heredado por subtipos.

Siempre puede usar la callablefunción incorporada para determinar si el objeto dado es invocable o no; o mejor aún, simplemente llámalo y captura TypeErrormás tarde callablese elimina en Python 3.0 y 3.1, use callable = lambda o: hasattr(o, '__call__')o isinstance(o, collections.Callable).

Ejemplo, una implementación de caché simplista:

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    

Uso:

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

Ejemplo de biblioteca estándar, archivo site.py, definición de funciones integradas exit()y 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
Encuentro el ejemplo del método de llamada muy engañoso porque lo mezcla con una receta para el almacenamiento en caché y los decoradores, que no agregan nada a la comprensión de la llamada
Florian Bösch

3
JF Sebastian, también acumulando más ejemplos que copias y pegas desde otro lugar que no son mínimos no ayuda.
Florian Bösch

20
@JF Sebastian: Es BS que más ejemplos realistas son mejores. Podría mostrarte un código realista que te haría llorar como ejemplo. Los ejemplos simples también funcionan, y funcionan mejor para ilustrar algo porque no distraen.
Florian Bösch

55
Está explicando qué se puede llamar, pero dio un ejemplo de cómo usar objetos invocables para definir un decorador. Sé que es un uso típico del exigible pero esto puede confundir a los lectores que sólo quieren saber lo que es exigible y cómo utilizar exigible . Prefiero la respuesta de @Florian Bösch.
KFL

2
@Kay: También me gusta la respuesta de @Florian Bösch (en su forma actual). por cierto, un decorador no es un uso típico de un "invocable". El más "callables" típicos son funciones / métodos tales como def f(): ..., y la clase de objetos como class C: ...es decir, f, ''.strip, len, y Ctodos son invocable. Las instancias que tienen un __call__()método en su clase son relativamente raras.
jfs

37

Un objeto invocable es un objeto que le permite usar paréntesis redondos () y eventualmente pasar algunos parámetros, al igual que las funciones.

Cada vez que define una función, Python crea un objeto invocable. Por ejemplo, podría definir la función func de estas formas (es lo mismo):

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

func = a()

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

Podría usar este método en lugar de métodos como doit o run , creo que es más claro ver obj () que obj.doit ()


37

Déjame explicarte al revés:

Considera esto...

foo()

... como azúcar sintáctica para:

foo.__call__()

¿Dónde foopuede haber cualquier objeto que responda __call__? Cuando digo cualquier objeto, lo digo en serio: tipos incorporados, sus propias clases y sus instancias.

En el caso de los tipos incorporados, cuando escribe:

int('10')
unicode(10)

Básicamente estás haciendo:

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

Esa es también la razón por la que no tienes foo = new inten Python: solo haces que el objeto de clase devuelva una instancia de él __call__. La forma en que Python resuelve esto es muy elegante en mi opinión.


Básicamente lo estás haciendo type(int).__call__(int, '10')y type(unicode).__call__(unicode, '10'). Los Dunders siempre son llamados en su clase, no a través de la instancia. Y nunca pasan por la metaclase tampoco. Para la mayoría de los casos, eso es solo una trampa, pero a veces es importante.
Físico loco

11

Un invocable es un objeto que tiene el __call__método. Esto significa que puede falsificar funciones invocables o hacer cosas interesantes como la aplicación de función parcial donde toma una función y agrega algo que la mejora o completa algunos de los parámetros, devolviendo algo que se puede llamar a su vez (conocido como Curry en círculos de programación funcional )

Ciertos errores tipográficos harán que el intérprete intente llamar a algo que no tenía intención, como (por ejemplo) una cadena. Esto puede producir errores en los que el intérprete intenta ejecutar una aplicación no invocable. Puede ver que esto sucede en un intérprete de Python haciendo algo como la transcripción a continuación.

[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__ hace que cualquier objeto sea invocable como una función.

Este ejemplo generará 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

En pocas palabras, un "invocable" es algo que se puede llamar como un método. La función integrada "invocable ()" le dirá si algo parece invocable, al igual que la comprobación de una propiedad de llamada . Las funciones son invocables como son las clases, las instancias de clase pueden ser invocables. Vea más sobre esto aquí y aquí .


5

En Python un invocable es un objeto cuyo tipo tiene un __call__método:

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

Tan sencillo como eso :)

Esto, por supuesto, se puede sobrecargar:

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

3

Verificar que la función o método de la clase sea invocable o no, eso significa que podemos llamar a esa función.

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
¿Estás seguro de callable(obj.__init___)que no tiene un guión bajo adicional (como en AttributeError)? Si no es así, ¿estás seguro de que la respuesta no es Truepara esa?
Físico loco

2

Es algo que puede poner "(args)" después y esperar que funcione. Un invocable suele ser un método o una clase. Se llaman métodos, se instancian las clases.


2

los invocables implementan el __call__método especial para que cualquier objeto con dicho método pueda invocarse.


Una instancia en la que defina __call__no se podrá llamar si la clase no define dicho método.
Físico loco

2

Llamable es un tipo o clase de "función o método integrado" con una llamada a método

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

Ejemplo: print es un objeto invocable. Con una función incorporada __call__ Cuando invoca la función de impresión , Python crea un objeto de tipo print e invoca su método __call__ pasando los parámetros si los hay.

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

Gracias. Saludos, Maris


1
Parte de la información aquí es incorrecta. Por ejemplo, "cuando invocas la printfunción, Python crea un objeto de tipo print e invoca su método__call__ ". Python no crea un objeto de impresión. Simplemente llama a algo equivalente a type(print).__call__(print, *args, **kwargs). Y la primera oración no tiene mucho sentido. Parece que está confundiendo un objeto invocable y "invoca" la función.
Físico loco
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.