Salut, Habr. Souvent lorsque l'on travaille avec des sĂ©quences, la question se pose de leur crĂ©ation. Il semble ĂȘtre habituĂ© Ă utiliser l'
inclusion de liste (compréhension de liste) et, dans les livres, à crier sur l'utilisation obligatoire de la fonction de
carte intégrée.
Dans cet article, nous examinerons ces approches pour travailler avec des séquences, comparer les performances et également déterminer dans quelles situations quelle approche est la meilleure.
Compréhension des listes
L'inclusion de liste est un mécanisme de génération de liste intégré à Python. Il n'a qu'une seule tùche - construire une liste. L'inclusion de liste crée une liste à partir de n'importe quel type itérable, transformant (filtrant) les valeurs entrantes.
Un exemple d'inclusion de liste simple pour générer une liste de carrés de nombres de 0 à 9:
squares = [x*x for x in range(10)]
Résultat:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
carte
map est une fonction intégrée au langage. Il accepte une fonction comme premier paramÚtre et un objet itérable comme deuxiÚme. Renvoie un générateur (Python 3.x) ou une liste (Python 2.x). Je choisirai Python 3.
Un exemple d'appel de la fonction map pour générer une liste de carrés de nombres de 0 à 9:
squares = list(map(lambda x: x*x, range(10)))
Résultat:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Comparaison des performances
Construire sans fonctions
à titre expérimental, nous considérerons les carrés des nombres de l'intervalle de 0 à 9 999 999:
python -m timeit -r 10 "[x*x for x in range(10000000)]" python -m timeit -r 10 "list(map(lambda x: x*x, range(10000000)))"
Résultats:
1 loop, best of 10: 833 msec per loop 1 loop, best of 10: 1.22 sec per loop
Comme vous pouvez le voir, la méthode de
compréhension de liste fonctionne environ 32% plus rapidement. Une fois démonté, il n'est pas possible d'obtenir des réponses complÚtes, car la fonction de carte «semble cacher les détails de son travail». Mais cela est probablement dû à l'appel constant de la fonction lambda, à l'intérieur duquel des calculs carrés sont déjà en cours. Dans le cas de la compréhension de liste, il suffit de calculer le carré.
Construire avec des fonctionnalités
à titre de comparaison, nous considérerons également les carrés des nombres, mais les calculs seront désormais à l'intérieur de la fonction:
python -m timeit -r 10 -s "def pow2(x): return x*x" "[pow2(x) for x in range(10000000)]" python -m timeit -r 10 -s "def pow2(x): return x*x" "list(map(pow2, range(10000000)))"
Résultats:
1 loop, best of 10: 1.41 sec per loop 1 loop, best of 10: 1.21 sec per loop
Cette fois, la situation est inversée. La méthode de la
carte Ă©tait 14% plus rapide. Dans cet exemple, les deux mĂ©thodes sont dans la mĂȘme situation. Les deux doivent appeler une fonction pour calculer le carrĂ©. Cependant, les optimisations internes de la fonction de carte lui permettent d'afficher de meilleurs rĂ©sultats.
Que choisir?
Voici la rÚgle pour choisir la bonne méthode:

Il peut y avoir des exceptions Ă cette rĂšgle, mais dans la plupart des cas, cela vous aidera Ă faire le bon choix!
la carte est-elle "plus sûre"?
Pourquoi beaucoup recommandent l'utilisation de la
carte . Le fait est que dans certains cas, la carte est en fait plus sûre que la compréhension de liste.
Par exemple:
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = [x*x for x in values]
Le résultat du programme sera le suivant:
a 3 b 3 c 3
Maintenant, réécrivez le mĂȘme code en utilisant la
carte :
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = map(lambda x: x*x, values)
Conclusion:
a a b b c c
Le plus observateur pouvait déjà remarquer à partir de la syntaxe de l'utilisation de
map qu'il s'agit de Python 2. En effet, dans le second python, il y avait un genre similaire de problÚme avec l'écrasement des variables. Cependant, dans Python 3, ce problÚme a été corrigé et n'est plus pertinent.
Les exemples dĂ©crits ci-dessus montreront les mĂȘmes rĂ©sultats. Il peut Ă©galement sembler que c'est une erreur stupide et vous ne ferez jamais une telle erreur, cependant, cela peut se produire lorsque vous transfĂ©rez simplement un bloc de code avec une boucle interne Ă partir d'un autre bloc. Une telle erreur peut vous coĂ»ter beaucoup de temps et de nerfs pour la rĂ©parer.
Conclusion
La comparaison a montré que chacune des méthodes est bonne dans sa situation.
- Si vous n'avez pas besoin de toutes les valeurs calculĂ©es Ă la fois (ou peut-ĂȘtre qu'elles ne sont pas du tout nĂ©cessaires), vous devez opter pour la carte . Ainsi, selon les besoins, vous demanderez une partie des donnĂ©es au gĂ©nĂ©rateur, tout en Ă©conomisant une grande quantitĂ© de mĂ©moire (Python 3. En Python 2, cela n'a pas de sens, car la carte renvoie une liste).
- Si vous devez calculer toutes les valeurs Ă la fois et que les calculs peuvent ĂȘtre effectuĂ©s sans utiliser de fonctions, vous devez alors faire un choix dans le sens de la comprĂ©hension de la liste . Comme le montrent les rĂ©sultats des expĂ©riences - il prĂ©sente un avantage significatif en termes de performances.
PS: Si j'ai raté quelque chose, je suis heureux d'en discuter avec vous dans les commentaires.