Soy un principiante en python, y acabo de aprender una técnica que involucra diccionarios y funciones. La sintaxis es fácil y parece algo trivial, pero mis sentidos de pitón tiemblan. Algo me dice que este es un concepto profundo y muy pitónico y no estoy comprendiendo su importancia. ¿Alguien puede ponerle un nombre a esta técnica y explicar cómo / por qué es útil?
La técnica es cuando tienes un diccionario de Python y una función que tienes la intención de usar. Inserta un elemento adicional en el dict, cuyo valor es el nombre de la función. Cuando esté listo para llamar a la función, emite la llamada indirectamente haciendo referencia al elemento dict, no a la función por su nombre.
El ejemplo con el que estoy trabajando es de Learn Python the Hard Way, 2nd Ed. (Esta es la versión disponible cuando se registra a través de Udemy.com ; lamentablemente, la versión HTML gratuita en vivo actualmente es Ed 3, y ya no incluye este ejemplo).
Parafrasear:
# make a dictionary of US states and major cities
cities = {'San Diego':'CA', 'New York':'NY', 'Detroit':'MI'}
# define a function to use on such a dictionary
def find_city (map, city):
# does something, returns some value
if city in map:
return map[city]
else:
return "Not found"
# then add a final dict element that refers to the function
cities['_found'] = find_city
Entonces las siguientes expresiones son equivalentes. Puede llamar a la función directamente o haciendo referencia al elemento dict cuyo valor es la función.
>>> find_city (cities, 'New York')
NY
>>> cities['_found'](cities, 'New York')
NY
¿Alguien puede explicar qué característica del lenguaje es esta y tal vez dónde se juega en la programación "real"? Este ejercicio de juguete fue suficiente para enseñarme la sintaxis, pero no me llevó hasta allí.
fuente
Respuestas:
El uso de un dict le permite traducir la clave en un invocable. Sin embargo, la clave no necesita ser codificada, como en su ejemplo.
Por lo general, esta es una forma de envío de llamadas, donde utiliza el valor de una variable para conectarse a una función. Digamos que un proceso de red le envía códigos de comando, una asignación de despacho le permite traducir los códigos de comando fácilmente en código ejecutable:
Tenga en cuenta que la función que llamamos ahora depende completamente de cuál es el valor
command
. La clave tampoco tiene que coincidir; ni siquiera tiene que ser una cadena, puede usar cualquier cosa que pueda usarse como clave y que se ajuste a su aplicación específica.El uso de un método de envío es más seguro que otras técnicas, como
eval()
, ya que limita los comandos permitidos a lo que definió de antemano. Ningún atacante va a pasar unals)"; DROP TABLE Students; --
inyección por una mesa de despacho, por ejemplo.fuente
dict
actos como el despachador (Gestor de mando, invocador, etc.).@Martijn Pieters hizo un buen trabajo explicando la técnica, pero quería aclarar algo de su pregunta.
Lo importante es saber que NO está almacenando "el nombre de la función" en el diccionario. Está almacenando una referencia a la función en sí. Puede ver esto usando a
print
en la función.f
es solo una variable que hace referencia a la función que definió. El uso de un diccionario le permite agrupar cosas similares, pero no es diferente de asignar una función a una variable diferente.Del mismo modo, puede pasar una función como argumento.
fuente
Tenga en cuenta que la clase Python es realmente un azúcar de sintaxis para el diccionario. Cuando tu lo hagas:
cuando usted llama
es realmente lo mismo que:
que, después de la resolución del nombre, es lo mismo que:
Una técnica útil es para asignar la entrada del usuario a las devoluciones de llamada. Por ejemplo:
Alternativamente, esto se puede escribir en clase:
la sintaxis de devolución de llamada que sea mejor depende de la aplicación particular y del gusto del programador. El primero es un estilo más funcional, el último está más orientado a objetos. El primero puede parecer más natural si necesita modificar las entradas en el diccionario de funciones dinámicamente (tal vez en función de la entrada del usuario); este último podría sentirse más natural si tiene un conjunto de asignaciones de preajustes diferentes que se pueden elegir dinámicamente.
fuente
5 * x
a5x
(perdona la analogía simple).Hay dos técnicas que me vienen a la mente a las que te puedes estar refiriendo, ninguna de las cuales es Pythonic, ya que son más amplias que un idioma.
1. La técnica de ocultación / encapsulación y cohesión de la información (generalmente van de la mano, así que las estoy agrupando).
Tiene un objeto que tiene datos y adjunta un método (comportamiento) que es altamente coherente con los datos. Si necesita cambiar la función, ampliar la funcionalidad o realizar cualquier otro cambio, las personas que llaman no necesitarán cambiar (suponiendo que no se necesiten datos adicionales).
2. Tablas de despacho
No es el caso clásico, porque solo hay una entrada con una función. Sin embargo, las tablas de despacho se utilizan para organizar diferentes comportamientos por una clave de modo que puedan buscar y llamar dinámicamente. No estoy seguro de si estás pensando en esto, ya que no te estás refiriendo a la función de manera dinámica, pero aún así obtienes un enlace tardío efectivo (la llamada "indirecta").
Compensaciones
Una cosa a tener en cuenta es que lo que hará funcionará bien con un espacio de nombres conocido de claves. Sin embargo, corre el riesgo de colisión entre los datos y las funciones con un espacio de nombres desconocido de claves.
fuente
Publico esta solución que creo que es bastante genérica y puede ser útil, ya que se mantiene simple y fácil de adaptar a casos específicos:
También se puede definir una lista donde cada elemento es un objeto de función y utilizar el
__call__
método incorporado. Créditos a todos por la inspiración y la cooperación."El gran artista es el simplificador", Henri Frederic Amiel
fuente