Estoy interesado en la comprensión del nuevo lenguaje de diseño de Python 3.x .
Disfruto, en Python 2.7, la función map
:
Python 2.7.12
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: [2, 3, 4]
Sin embargo, en Python 3.x las cosas han cambiado:
Python 3.5.1
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: <map at 0x4218390>
Entiendo el cómo, pero no pude encontrar una referencia al por qué. ¿Por qué los diseñadores de lenguajes tomaron esta decisión, que, en mi opinión, presenta un gran dolor? ¿Fue esto para luchar con los desarrolladores al ceñirse a las listas de comprensión?
OMI, la lista se puede pensar naturalmente como Functors ; y de alguna manera se ha pensado que pienso de esta manera:
fmap :: (a -> b) -> f a -> f b
python
python-3.x
NoIdeaCómo arreglar esto
fuente
fuente
map
simplemente iteraron sobre el resultado. Crear una lista cuando no la necesita es ineficaz, por lo que los desarrolladores decidieron hacerlamap
floja. Hay mucho que ganar aquí para el rendimiento y no mucho que perder (si necesita una lista, solo pida una ...list(map(...))
).Respuestas:
Creo que la razón por la cual un mapa todavía existe en absoluto cuando las expresiones generadoras también existen, es que puede tomar múltiples argumentos iterador que están todos en bucle una y pasados a la función:
>>> list(map(min, [1,2,3,4], [0,10,0,10])) [0,2,0,4]
Eso es un poco más fácil que usar zip:
>>> list(min(x, y) for x, y in zip([1,2,3,4], [0,10,0,10]))
De lo contrario, simplemente no agrega nada sobre las expresiones del generador.
fuente
c = list(map(max, [1,2,3,4], [0,10,0,10, 99]))
en python 2 y en python 3.Debido a que devuelve un iterador, omite almacenar la lista de tamaño completo en la memoria. Para que pueda repetirlo fácilmente en el futuro sin causar ningún dolor en la memoria. Es posible que ni siquiera necesite una lista completa, sino una parte de ella, hasta que se alcance su condición.
Puede encontrar útiles estos documentos , los iteradores son increíbles.
fuente
Guido responde a esta pregunta aquí : " ya que crear una lista sería un desperdicio ".
También dice que la transformación correcta es usar un
for
bucle regular .La conversión
map()
de 2 a 3 podría no ser solo un simple caso de pegarse unalist( )
ronda. Guido también dice:"Si las secuencias de entrada no tienen la misma longitud,
map()
se detendrá en la terminación de la más corta de las secuencias. Para una compatibilidad total conmap()
Python 2.x, también envuelva las secuenciasitertools.zip_longest()
, por ejemplose convierte en
"
fuente
map()
invoca por los efectos secundarios de la función , no por su uso como functor.zip_longest
está mal. usted tiene que utilizaritertools.starmap
para que sea equivalente:list(starmap(func, zip_longest(*sequences)))
. Esto se debe a quezip_longest
produce tuplas, por lofunc
que recibiría un únicon
argumento -uple en lugar den
argumentos distintos como es el caso al llamarmap(func, *sequences)
.En Python 3, muchas funciones (no solo
map
perozip
,range
y otras) devuelven un iterador en lugar de la lista completa. Es posible que desee un iterador (por ejemplo, para evitar mantener la lista completa en la memoria) o puede querer una lista (por ejemplo, para poder indexar).Sin embargo, creo que la razón clave del cambio en Python 3 es que, si bien es trivial convertir un iterador en una lista utilizando
list(some_iterator)
el equivalente inverso,iter(some_list)
no se logra el resultado deseado porque la lista completa ya se ha creado y se ha guardado en la memoria.Por ejemplo, en Python 3
list(range(n))
funciona bien ya que hay un bajo costo para construir elrange
objeto y luego convertirlo en una lista. Sin embargo, en Python 2iter(range(n))
no se guarda memoria porque la lista completa se construyerange()
antes de que se construya el iterador.Por lo tanto, en Python 2, se requieren funciones separadas para crear un iterador en lugar de una lista, como
imap
formap
(aunque no son del todo equivalentes ),xrange
forrange
,izip
forzip
. Por el contrario, Python 3 solo requiere una única función, ya que unalist()
llamada crea la lista completa si es necesario.fuente
itertools
iteradores de retorno. Además, no vería los iteradores como listas diferidas, ya que las listas se pueden iterar varias veces y se puede acceder a ellas de forma aleatoria.map
objetos de Python 3 tienen unnext()
método. Losrange
objetos de rango de Python 3 no son estrictamente iteradores, lo séfoo = map(lambda x: x, [1, 2, 3])
devuelve un objeto de mapafoo
. hacerfoo.next()
vuelve con un error:'map' object has no attribute 'next'
__
están reservados para Python; sin esa reserva, tiene el problema de distinguir las cosas para las quenext
es solo un método (no son realmente iteradores) y las cosas que son iteradores. En la práctica, debe omitir los métodos y simplemente usar lanext()
función (por ejemplonext(foo)
), que funciona correctamente en todas las versiones de Python a partir de la 2.6. Es la misma forma en que lo usalen(foo)
, aunquefoo.__len__()
funcionaría bien; Los métodos dunder generalmente no están destinados a ser llamados directamente, sino implícitamente como parte de alguna otra operación.