95 votes

Pourquoi la carte renvoie-t-elle un objet de la carte plutôt qu'une liste dans Python 3?

Je cherche à comprendre le nouveau langage de conception de Python 3.x.

J'aime, en Python 2.7, la fonction map:

Python 2.7.12
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: [2, 3, 4]

Toutefois, en Python 3.x, les choses ont changé:

Python 3.5.1
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: <map at 0x4218390>

Je comprends le comment, mais je ne pouvais pas trouver une référence à la raison. Pourquoi la langue concepteurs de faire ce choix, ce qui, à mon avis, présente une grande partie de la douleur. Etait-ce bras de fer développeurs à s'interprétations de la liste?

OMI, la liste peut être naturellement pensé que les Foncteurs; et j'ai été en quelque sorte été pensé pour penser de cette façon:

fmap :: (a -> b) -> f a -> f b

41voto

RemcoGerlich Points 5676

Je pense que la raison pour laquelle la carte existe toujours du tout quand les expressions du générateur existent également, est que cela peut prendre plusieurs arguments iterator qui sont tous bouclées sur et est passé dans la fonction:

 >>> list(map(min, [1,2,3,4], [0,10,0,10]))
[0,2,0,4]
 

C'est un peu plus facile que d'utiliser zip:

 >>> list(min(x, y) for x, y in zip([1,2,3,4], [0,10,0,10]))
 

Sinon, cela n'ajoute rien aux expressions du générateur.

28voto

vishes_shell Points 10206

Parce qu'elle renvoie un itérateur, il omettre le stockage de la taille complète de la liste dans la mémoire. De sorte que vous pouvez facilement parcourir, dans l'avenir, de ne pas prendre la douleur de la mémoire. Éventuellement, vous n'avez même pas besoin d'une liste complète, mais la partie d'elle, jusqu'à ce que votre état est atteint.

Vous pouvez trouver ce docs utiles, les itérateurs sont impressionnantes.

Un objet représentant un flux de données. Les appels répétés à l'itérateur de l' __next__() méthode (ou de le transmettre à la fonction intégrée next()) rendement de l'successives des éléments dans le flux. Lorsque plus de données sont disponibles, un StopIteration d'exception est soulevée à la place. À ce stade, l'itérateur objet est épuisé et toutes les autres appels de ses __next__() méthode de la juste soulever StopIteration de nouveau. Les itérateurs sont tenus d'avoir un __iter__() méthode qui renvoie l'itérateur objet lui-même, de sorte que chaque itérateur est également itérable et peut être utilisé dans la plupart des endroits où d'autres iterables sont acceptés. Une exception notable est le code qui essaie plusieurs itération passe. Un conteneur d'objet (comme un list) produit un nouvel itérateur chaque fois que vous passez à l' iter() de la fonction ou de l'utiliser dans une boucle for. D'essayer cela avec un itérateur va juste retourner la même épuisé itérateur l'objet utilisé dans l'itération précédente pass, le faisant apparaître comme un conteneur vide.

14voto

cdarke Points 8020

Guido répond à cette question ici: "depuis la création d'une liste serait juste gaspillage".

Il dit aussi que la transformation correcte est d'utiliser un for boucle.

Convertir map() de 2 à 3 peut ne pas être juste un cas simple de coller une list( ) autour d'elle. Guido dit aussi:

"Si l'entrée séquences ne sont pas d'égale longueur, map() arrêtera à la fin de la plus courte des séquences. Pour une compatibilité totale avec map() de Python 2.x, envelopper les séquences en itertools.zip_longest(), par exemple

map(func, *sequences)

devient

list(map(func, itertools.zip_longest(*sequences)))

"

12voto

Chris_Rands Points 15161

En Python 3, beaucoup de fonctions (pas seulement map mais zip, range et autres) retourne un itérateur plutôt que la liste complète. Vous pourriez vouloir un itérateur (par exemple, pour éviter de tenir l'ensemble de la liste dans la mémoire) ou vous pouvez une liste (par exemple, pour être en mesure de l'indice).

Cependant, je pense que la principale raison pour laquelle le changement de Python 3 est que, même s'il est trivial de convertir un itérateur d'une liste à l'aide de list(some_iterator) l'inverse équivalent iter(some_list) ne permet pas d'atteindre le résultat souhaité, car la liste complète a déjà été construit et la mémoire.

Par exemple, dans Python 3 list(range(n)) fonctionne très bien car il y a peu de coûts pour la construction de l' range objet, puis de le convertir à une liste. Toutefois, en Python 2 iter(range(n)) n'enregistre pas de mémoire, parce que la liste complète est construite en range() avant l'itérateur est construit.

Par conséquent, en Python 2, fonctions distinctes sont nécessaires pour créer un itérateur plutôt que d'une liste, comme imap pour map (même si ils sont pas tout à fait équivalent), xrange pour range, izip pour zip. En revanche Python 3, il suffit d'une seule fonction en tant que list() appel crée la liste complète si nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X