2010-07-30 18 views
12

¿Cuáles son las opiniones de las personas sobre el uso del __call__. Raramente lo he visto usado, pero creo que es una herramienta muy útil para usar cuando sabes que una clase se usará para algún comportamiento predeterminado.¿Cuándo se usa __call__ una buena idea?

+1

-1: No es una pregunta de "opinión". No es "práctico" para las cosas. Simplemente ** se requiere ** para hacer un ** objeto invocable **. –

+0

La pregunta está más centrada en cuándo es beneficioso tener objetos invocables. El método '__call__' es simplemente el vehículo para lograr eso. Estoy más interesado en el comportamiento que en el mecanismo para lograr el comportamiento. Si desea votar la pregunta, debe hacerlo con el botón de flecha, en lugar de su comentario. –

+1

Por lo general, se considera educado indicar mediante un comentario por qué una publicación fue rechazada y si la publicación se puede mejorar. Suponiendo que el comentario se hace _politely_, por supuesto. –

Respuesta

15

Creo que su intuición es la correcta.

Históricamente, los objetos invocables (o lo que a veces he oído llamar "funtores") se han utilizado en el mundo OO para simular cierres. En C++ son frecuentemente indispensables.

Sin embargo, __call__ tiene un poco de competencia en el mundo de Python:

  • Un método llamado regular, cuyo comportamiento puede ser a veces mucho más fácilmente deducir del nombre. Puede convertir a un método vinculado, que se puede llamar como una función.
  • Un cierre, obtenido al devolver una función que está definida en un bloque anidado.
  • Una lambda, que es una forma limitada pero rápida de realizar un cierre.
  • Generadores y coroutines, cuyos cuerpos mantienen el estado acumulado como un functor.

Yo diría que el momento de usar __call__ es cuando no se beneficia de una de las opciones anteriores. Verifique los siguientes criterios, quizás:

  • Su objeto tiene estado.
  • Hay un claro comportamiento "primario" para su clase que es un poco tonto de nombrar. P.ej.si se encuentra escribiendo run() o doStuff() o go() o el popular doRun() siempre redundante, puede tener un candidato.
  • Su objeto tiene un estado que excede el que se esperaría de una función del generador.
  • Su objeto envuelve, emula o abstrae el concepto de una función.
  • Su objeto tiene otros métodos auxiliares que pertenecen conceptualmente a su comportamiento principal.

Un ejemplo que me gusta son los objetos de comando UI. Diseñado para que su tarea principal sea ejecutar el comando, pero con métodos adicionales para controlar su visualización como un elemento del menú, por ejemplo, me parece que es el tipo de cosas para las que aún desea un objeto llamable.

4

Úselo si necesita que sus objetos a ser exigible, eso es lo que está ahí para

No estoy seguro de lo que entendemos por comportamiento predeterminado

Un lugar que he encontrado que es particularmente útil es cuando se usa un contenedor o somesuch donde el objeto se llama profundamente dentro de algún framework/biblioteca.

+0

Urgh. La pregunta parece realmente tonta ahora. Por comportamiento predeterminado quise decir que aunque las clases a menudo tienen varios métodos, a menudo hay un flujo de trabajo muy regular desde los datos hasta la salida de datos. Me preguntaba si '__call__' se puede usar para aumentar la velocidad de acceso a ese flujo de trabajo estándar. –

+0

Bueno, un poco. No sé exactamente qué quiere decir con "aumentar la velocidad de acceso a ese flujo de trabajo estándar". '__call__' en general no tiene nada que ver con la velocidad. Puede guardar una búsqueda de atributos si usa 'obj()' en lugar de algo como 'obj.function_name()' pero eso no vale la pena mencionarlo. – nils

+0

@Tim McNamara: Correcto. La pregunta es tonta. Particularmente la parte de "opinión" de eso. –

1

En términos más generales, Python tiene un lote de métodos de doble subrayado. Están ahí por una razón: son la forma de Python de sobrecargar a los operadores. Por ejemplo, si desea una nueva clase en la que además, no sé, imprime "foo", defina los métodos __add__ y __radd__. No hay nada intrínsecamente bueno o malo en esto, así como tampoco hay nada bueno o malo en usar los bucles for.

De hecho, usar __call__ es a menudo el enfoque más Pythonic, porque fomenta la claridad del código. Puede reemplazar MyCalculator.calculateValues(foo) con MyCalculator(foo), por ejemplo.

+0

¿Es MyCalculator (foo) o theCalculatorObject (foo)? – Nabin

0

Se usa generalmente cuando la clase se utiliza como función con contexto de instancia, como DecoratorClass que se usaría como @DecoratorClass('some param'), por lo que 'algún parámetro' se almacenaría en el espacio de nombres de la instancia y se llamaría instancia como decorador real.

No es muy útil cuando su clase proporciona algunos métodos diferentes, ya que generalmente no es obvio cuál sería la llamada, y explícito es mejor que implícito en estos casos.

Cuestiones relacionadas