Sé que el __call__
método en una clase se activa cuando se llama a la instancia de una clase. Sin embargo, no tengo idea de cuándo puedo usar este método especial, porque uno simplemente puede crear un nuevo método y realizar la misma operación realizada en el __call__
método y en lugar de llamar a la instancia, puede llamar al método.
Realmente agradecería si alguien me da un uso práctico de este método especial.
python
methods
call
magic-methods
mohi666
fuente
fuente
__call__
está oculto a simple vista; es cómo instanciar una clase:x = Foo()
es realmentex = type(Foo).__call__(Foo)
, donde__call__
está definida por la metaclase deFoo
.Respuestas:
El módulo de formularios de Django utiliza el
__call__
método muy bien para implementar una API consistente para la validación de formularios. Puede escribir su propio validador para un formulario en Django como una función.Django tiene algunos validadores integrados predeterminados, como validadores de correo electrónico, validadores de URL, etc., que en general se encuentran bajo el paraguas de los validadores RegEx. Para implementarlos limpiamente, Django recurre a clases invocables (en lugar de funciones). Implementa la lógica de validación Regex predeterminada en un RegexValidator y luego extiende estas clases para otras validaciones.
Ahora tanto su función personalizada como el EmailValidator incorporado se pueden invocar con la misma sintaxis.
Como puede ver, esta implementación en Django es similar a lo que otros han explicado en sus respuestas a continuación. ¿Se puede implementar de alguna otra manera? Podría, pero en mi humilde opinión, no será tan legible ni tan fácilmente extensible para un gran marco como Django.
fuente
Este ejemplo utiliza la memorización , básicamente almacenando valores en una tabla (diccionario en este caso) para que pueda buscarlos más tarde en lugar de volver a calcularlos.
Aquí usamos una clase simple con un
__call__
método para calcular factoriales (a través de un objeto invocable ) en lugar de una función factorial que contiene una variable estática (ya que eso no es posible en Python).Ahora tiene un
fact
objeto invocable, como cualquier otra función. Por ejemploY también tiene estado.
fuente
fact
objeto que sea indexable ya que su__call__
función es esencialmente un índice. También usaría una lista en lugar de un dict, pero solo soy yo.__call__
, ser simple y nada más.Lo encuentro útil porque me permite crear API que son fáciles de usar (tiene algún objeto invocable que requiere algunos argumentos específicos) y es fácil de implementar porque puede usar prácticas orientadas a objetos.
El siguiente es el código que escribí ayer que hace una versión de los
hashlib.foo
métodos que procesan archivos enteros en lugar de cadenas:Esta implementación me permite usar las funciones de manera similar a las
hashlib.foo
funciones:Por supuesto, podría haberlo implementado de una manera diferente, pero en este caso parecía un enfoque simple.
fuente
__call__
te brinda una herramienta que te permite usar técnicas OO para resolver problemas.isinstance
o algo similar.__call__
método en lugar de un cierre es cuando se trata del módulo de multiprocesamiento, que utiliza el decapado para pasar información entre procesos. No puede encurtir un cierre, pero puede encurtir una instancia de una clase.__call__
también se usa para implementar clases de decorador en python. En este caso, se llama a la instancia de la clase cuando se llama al método con el decorador.fuente
Sí, cuando sabes que estás tratando con objetos, es perfectamente posible (y en muchos casos aconsejable) usar una llamada a un método explícito. Sin embargo, a veces se trata de código que espera objetos invocables, por lo general, funciones, pero gracias a
__call__
él puede construir objetos más complejos, con datos de instancia y más métodos para delegar tareas repetitivas, etc. que todavía son invocables.Además, a veces está utilizando tanto objetos para tareas complejas (donde tiene sentido escribir una clase dedicada) como objetos para tareas simples (que ya existen en funciones o que se escriben más fácilmente como funciones). Para tener una interfaz común, debe escribir clases pequeñas que envuelvan esas funciones con la interfaz esperada, o mantener las funciones de las funciones y hacer que los objetos más complejos sean invocables. Tomemos los hilos como ejemplo. Los
Thread
objetos del módulo de biblioteca estándarthreading
quieren un llamado comotarget
argumento (es decir, como acción a realizar en el nuevo hilo). Con un objeto invocable, no está restringido a funciones, también puede pasar otros objetos, como un trabajador relativamente complejo que obtiene tareas de otros subprocesos y las ejecuta secuencialmente:Este es solo un ejemplo fuera de mi cabeza, pero creo que ya es lo suficientemente complejo como para justificar la clase. Hacer esto solo con funciones es difícil, al menos requiere devolver dos funciones y eso se vuelve lentamente complejo. Se podría cambiar el nombre
__call__
a otra cosa y pasar un método enlazado, pero eso hace que el código que crea el hilo sea un poco menos obvio, y no agrega ningún valor.fuente
__call__
solía usar instancias de clase (en lugar de funciones) como aplicaciones WSGI. Aquí hay un ejemplo de "La guía definitiva para pilones": Uso de instancias de clasesLos decoradores basados en clases usan
__call__
para hacer referencia a la función envuelta. P.ej:Hay una buena descripción de las diversas opciones aquí en Artima.com
fuente
El
__call__
método IMHO y los cierres nos dan una forma natural de crear un patrón de diseño STRATEGY en Python. Definimos una familia de algoritmos, encapsulamos cada uno, los hacemos intercambiables y al final podemos ejecutar un conjunto común de pasos y, por ejemplo, calcular un hash para un archivo.fuente
Me topé con un uso de
__call__()
concierto con el__getattr__()
que creo que es hermoso. Le permite ocultar múltiples niveles de una API JSON / HTTP / (sin embargo, serializada) dentro de un objeto.La
__getattr__()
parte se encarga de devolver iterativamente una instancia modificada de la misma clase, completando un atributo más a la vez. Luego, después de que toda la información se haya agotado, se__call__()
hace cargo de cualquier argumento que haya pasado.Con este modelo, puede, por ejemplo, realizar una llamada como
api.v2.volumes.ssd.update(size=20)
, que termina en una solicitud PUT ahttps://some.tld/api/v2/volumes/ssd/update
.El código particular es un controlador de almacenamiento en bloque para un cierto back-end de volumen en OpenStack, puede consultarlo aquí: https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py
EDITAR: Se actualizó el enlace para apuntar a la revisión maestra.
fuente
Especifique
__metaclass__
ay anule el__call__
método, y haga que el método de las metaclases especificadas__new__
devuelva una instancia de la clase, si tiene una "función" con los métodos.fuente
Podemos usar el
__call__
método para usar otros métodos de clase como métodos estáticos.fuente
Un ejemplo común es
__call__
infunctools.partial
, aquí hay una versión simplificada (con Python> = 3.5):Uso:
fuente
El operador de llamada de función.
El método __call__ puede usarse para redefinir / reinicializar el mismo objeto. También facilita el uso de instancias / objetos de una clase como funciones al pasar argumentos a los objetos.
fuente
Me parece un lugar bueno para usar los objetos que se puede llamar, los que definen
__call__()
, es decir cuando se utilizan las capacidades de programación en Python funcionales, tales comomap()
,filter()
,reduce()
.El mejor momento para usar un objeto invocable sobre una función simple o una función lambda es cuando la lógica es compleja y necesita retener algún estado o utiliza otra información que no se pasa a la
__call__()
función.Aquí hay un código que filtra los nombres de archivos según su extensión de nombre de archivo utilizando un objeto invocable y
filter()
.Llamable:
Uso:
Salida:
fuente
Esto es demasiado tarde pero estoy dando un ejemplo. Imagina que tienes una
Vector
clase y unaPoint
clase. Ambos tomanx, y
como argumentos posicionales. Imaginemos que desea crear una función que mueva el punto que se colocará en el vector.4 soluciones
put_point_on_vec(point, vec)
Que sea un método en la clase de vector. p.ej
my_vec.put_point(point)
Point
clase.my_point.put_on_vec(vec)
Vector
implementa__call__
, para que pueda usarlo comomy_vec_instance(point)
En realidad, esto es parte de algunos ejemplos en los que estoy trabajando para obtener una guía de métodos dunder explicada con Maths que lanzaré tarde o temprano.
Dejé la lógica de mover el punto en sí porque esto no es de lo que se trata esta pregunta
fuente