2009-05-17 10 views
10

¿Representa el mapa() iterar a través de la lista como "para"? ¿Hay algún valor en usar map vs for?¿Hay algún valor en usar map() vs for?

Si es así, ahora mismo mi código es el siguiente:

for item in items: 
    item.my_func() 

Si tiene sentido, me gustaría hacer que el mapa(). ¿Es eso posible? ¿Cómo es un ejemplo?

Respuesta

23

Usted podría utilizar map en lugar del bucle for que has demostrado, pero ya no se presenta a utilizar el resultado de item.my_func(), esto se recomienda no . map se debe utilizar si desea aplicar una función sin efectos secundarios a todos los elementos de una lista. En todas las demás situaciones, use un for-loop explícito.

Además, a partir de Python 3.0 map devuelve un generador, así que en ese caso map no se comportará de la misma (a menos que se evalúa de forma explícita todos los elementos devueltos por el generador, por ejemplo llamando list en él).


Editar: kibibu pregunta en los comentarios para una aclaración sobre por qué map 's primer argumento no debe ser una función con efectos secundarios. Voy a dar respuesta a esa pregunta un disparo:

map se supone que se aprobó una función fin the mathematical sense. En tales circunstancias, no importa en qué orden se aplica f a los elementos del segundo argumento (siempre que sean devueltos en su orden original, por supuesto). Más importante aún, bajo esas circunstancias, map(g, map(f, l)) es semánticamente equivalente a map(lambda x: g(f(x)), l), , independientemente del orden en que f y g se aplican a sus entradas respectivas.

P. ej., No importa si map regresa y el iterador o una lista completa a la vez. Sin embargo, si f y/o g causan efectos secundarios, a continuación, esta equivalencia está garantizada solo si la semántica de map(g, map(f, l)) son tales que en cualquier etapa g se aplica a los primeros n elementos devueltos por map(f, l) antes map(f, l) aplica f a la (n + 1) ​ elemento st de l. (Lo que significa que map debe realizar la iteración más perezoso posible --- la que lo hace en Python 3, pero no en Python 2!)

Yendo un paso más allá: incluso si asumimos la implementación de Python 3 de map, la equivalencia semántica puede romperse fácilmente si la salida de map(f, l) es, por ejemplo, pasó a través de itertools.tee antes de ser suministrado a la llamada externa map.

La discusión anterior puede parecer de naturaleza teórica, pero a medida que los programas se vuelven más complejos, se vuelven más difíciles de razonar y, por lo tanto, más difíciles de depurar. Asegurarse de que algunas cosas son invariables alivia un poco ese problema, y ​​de hecho puede prevenir toda una clase de errores.

Por último, map recuerda a muchas personas su contraparte verdaderamente funcional en varios idiomas (puramente) funcionales. Pasarle una "función" con efectos secundarios confundirá a esas personas. Por lo tanto, teniendo en cuenta que la alternativa (es decir, utilizar un bucle explícito) no es más difícil de implementar que una llamada al map, se recomienda encarecidamente que se restrinja el uso de map a aquellos casos en los que la función que se va a aplicar no cause efectos secundarios .

+0

¡Gracias a todos! – roder

+0

¿Por qué no se recomienda? ¿Es una cuestión de semántica o algún tipo de proceso distribuido (donde los efectos secundarios rompen el paralelismo)? – kibibu

+1

@kibibu: Empecé a responder a su pregunta, pero terminé con demasiado texto para contener este campo de comentarios. Así que actualicé la respuesta :) ¡Cómo ayuda esto! (En cuanto a su comentario sobre el procesamiento distribuido del iterable: aunque * podría * ser citado como un argumento adicional cuando se habla de 'map' en otros idiomas, no creo que Python (actualmente) realice optimizaciones de ese tipo). – Stephan202

-3
map(lambda item: item.my_func(), items) 
+1

Esto funciona, pero no responde a la pregunta de por qué es mejor que usar un bucle for (es decir, no lo es). – Kiv

1

La principal ventaja de map es cuando desea obtener el resultado de un cálculo en cada elemento de una lista. Por ejemplo, este fragmento se duplica cada valor en una lista:

map(lambda x: x * 2, [1,2,3,4]) #=> [2, 4, 6, 8] 

Es importante señalar que map devuelve una nueva lista con los resultados. No modifica la lista original en su lugar.

Para hacer lo mismo con for, debería crear una lista vacía y agregar una línea adicional al cuerpo for para agregar el resultado de cada cálculo a la nueva lista. La versión map es más concisa y funcional.

+4

Las comprensiones de listas son aún más concisas, por ej. [x * 2 para x en [1,2,3,4]) en su ejemplo. – Kiv

5

Usted puede escribir este mapa utilizando la siguiente manera:

map(cls.my_func, items) 

sustitución de CLS con la clase de los elementos que está interactuando sobre.

Según lo mencionado por Stephan202, esto es no recomendado en este caso.

Como regla, si desea crear una nueva lista aplicando alguna función a cada elemento de la lista, utilice el mapa. Esto tiene el significado implícito de que la función no tiene ningún efecto secundario y, por lo tanto, podría (potencialmente) ejecutar el mapa en paralelo.

Si no desea crear una nueva lista, o si la función tiene efectos secundarios, use un ciclo for. Este es el caso en tu ejemplo.

2

Hay una ligera diferencia semántica, que probablemente esté cerrada en la especificación de Python. El mapa es explícitamente paralelizable, mientras que para solo en situaciones especiales. Código puede romper desde para, pero solo escapar con excepción de mapa.

En mi opinión mapa no debe también garantizar el orden de aplicación de función, mientras que para necesidad. AFAIK ninguna implementación de Python actualmente puede hacer esta paralelización automática.

2

Puede cambiar su map por un marco de computación distribuida O con múltiples subprocesos u O bien, si lo necesita. Disco es un ejemplo de framework distribuido, resistente a fallas erlang-and-python. Lo configuré en 2 cajas de 8 núcleos y ahora mi programa se ejecuta 16 veces más rápido, gracias al clúster Disco, sin embargo tuve que volver a escribir mi programa desde la comprensión de la lista y para los bucles para asignar/reducir.

Es lo mismo que escribir un programa usando bucles for y enumerar comprensiones y mapa/reducir, pero cuando lo necesita para ejecutar en un clúster, puede hacerlo casi gratis si utilizó map/reduce.Si no lo hizo, bueno, tendrá que volver a escribir.

Cuidado: hasta donde yo sé, Python 2.x devuelve una lista en lugar de un iterador del mapa. He oído que esto puede evitarse usando iter.imap() (aunque nunca lo he usado).

2

Utilice un for-loop explícito cuando no necesite una lista de resultados hacia atrás (por ejemplo, funciones con efectos secundarios).

Use una lista de comprensión cuando necesite una lista de resultados anteriores (por ejemplo, funciones que devuelven un valor basado directamente en la entrada).

Utilice el mapa() cuando intente convencer a los usuarios de Lisp de que Python vale la pena su uso. ;)

0

El mapa a veces puede ser más rápido para las funciones integradas que la codificación manual de un bucle for. Intenta sincronizar el mapa (str, rango (1000000)) vs. un ciclo similar para.

Cuestiones relacionadas