French (Français) translation by Stéphane Esteve (you can also view the original English article)
La liste en compréhension vous permet d'écrire des boucles for
plus concises. Très utiles dès lors que vous créez de nouvelles listes basées sur des pré-existantes ou des itérables. Par exemple, vous pouvez utiliser une liste en compréhension pour créer une liste de carrés issus d'une autre liste de nombres. Ainsi, cette nouvelle liste toute fraîche devient une déclinaison disponible de la liste originale.
Gardez à l'esprit que vous ne pouvez pas rédiger chaque boucle for en liste de compréhension. Autre détail : le qualificatif "liste en compréhension" semble un peu confus car il supposerait que son traitement serait réservé seulement qu'aux listes. En réalité, le mot "liste" dans liste en compréhension sert juste à qualifier tout type de boucle qui parcoure tout itérable dans Python, et produit au final, une liste.
Boucles et listes en compréhension
Une liste en compréhension des plus banales, sans sollicitation d'aucune condition, prend cette forme :
1 | [<the_expression> for <the_element> in <the_iterable>] |
Commençons par écrire une boucle très simple for
pour lister les 15 premiers multiples de 5. D'abord, créons une liste vide. Ensuite, vous devez itérer à travers un ensemble de nombres et les multiplier par 5. Cette nouvelle séquence de nombres contiendra ainsi des multiples de 5.
1 | multiples = [] |
2 | |
3 | for n in range(1,16): |
4 | multiples.append(n*5) |
5 | |
6 | print(multiples) |
7 | # [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75] |
La boucle for
ci-dessus est construire simplement selon cette structure :
1 | for <the_element> in <the_iterable>: |
2 | <the_expression> |
Si vous la comparez avec l'enveloppe de la liste en compréhension que vous avez observer auparavant, vous notez que <the_element>
est n
, <the_iterable>
est range(1,16)
, et que <the_expression>
est n*5
. Insérer ces valeurs dans la liste en compréhension produira le résultat suivant :
1 | multiples = [n*5 for n in range(1,15)] |
2 | |
3 | multiples |
4 | # [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70] |
De la même façon, vous pouvez avoir une liste des cubes pour chaque nombre défini, comme ceci :
1 | cubes = [n**3 for n in range(1,16)] |
2 | |
3 | print(cubes) |
4 | #[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331, 1728, 2197, 2744, 3375] |
Les conditions dans les listes en compréhension
Vous pouvez également insérer une condition if
pour filtrer certaines valeurs de la liste résultante. En ce cas, la liste en compréhension prends la forme suivante :
1 | [<the_expression> for <the_element> in <the_iterable> if <the_condition>] |
Parmi les illustrations évidentes de ce type de compréhension, ce serait l'obtention des nombres pairs selon un écart de nombre donné. Produisons ceci à travers une boucle for
:
1 | evens = [] |
2 | |
3 | for n in range(1,21): |
4 | if n%2 == 0: |
5 | evens.append(n) |
6 | |
7 | print(evens) |
8 | # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] |
Nous parvenons aussi au même résultat selon la liste de compréhension suivante :
1 | evens = [n for n in range(1,21) if n%2 == 0] |
2 | |
3 | print(evens) |
4 | # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] |
Un exemple encore plus compliqué de liste de compréhension serait d'introduire en son sein des expressions conditionnelles comme .. if .. else ..
Dans ce cas, l'ordre dans lequel vous déclarez tous ces états dans cette liste sera différent d'une condition if
classique. Si cette condition if
est nécessaire, elle sera inscrite en fin de la compréhension. Toutefois, dans le cas d'une expression .. if .. else ..
,les positions respectives de la boucle for
et de l'expression conditionnelle sont interchangeables. Une autre possibilité :
1 | [<the_expression> if <the_condition> else <other_expression> for <the_element> in <the_iterable>] |
Commençons par écrire cette expression conditionnelle verbeuse .. if .. else ..
pour calculer les carrés des nombres pairs et les cubes des nombres impaires, selon un écart prédéfini.
1 | squares_cubes = [] |
2 | |
3 | for n in range(1,16): |
4 | if n%2 == 0: |
5 | squares_cubes.append(n**2) |
6 | else: |
7 | squares_cubes.append(n**3) |
8 | |
9 | print(squares_cubes) |
10 | # [1, 4, 27, 16, 125, 36, 343, 64, 729, 100, 1331, 144, 2197, 196, 3375] |
L'expression conditionnelle ci-dessous suit la structure suivante :
1 | for <the_element> in <the_iterable>: |
2 | if <the_condition>: |
3 | <the_expression> |
4 | else: |
5 | <other_expression> |
Placer les valeurs correspondantes au bon endroit donnera cette liste en compréhension :
1 | squares_cubes = [n**2 if n%2 == 0 else n**3 for n in range(1,16)] |
2 | |
3 | print(squares_cubes) |
4 | # [1, 4, 27, 16, 125, 36, 343, 64, 729, 100, 1331, 144, 2197, 196, 3375] |
Les liste en compréhension dans des boucles imbriquées
Il est aussi possible d'utiliser des boucles imbriquées à l'intérieur d'une liste en compréhension . En fait, il n'y a aucune limitation sur la quantité de boucles for
à glisser dedans. Cependant, ayez à l'esprit que l'ordre de ces boucles doit être exactement le même à la fois dans le code original et la liste en compréhension. Par ailleurs, vous pouvez insérer une condition if
optionnelle après chaque boucle for
. Une liste en compréhension comprenant quelques boucles imbriquées for
aura donc cette allure :
1 | [ <the_expression> for <element_a> in <iterable_a> (optional if <condition_a>) |
2 | for <element_b> in <iterable_b> (optional if <condition_b>) |
3 | for <element_c> in <iterable_c> (optional if <condition_c>) |
4 | ... and so on ...] |
Les exemples qui suivent ici devraient être beaucoup plus éclairants. Sont présentes deux boucles imbriquées, et en les multipliant l'une à l'autre, on obtient une table de multiplications.
1 | multiplications = [] |
2 | |
3 | for i in range(1, 4): |
4 | for n in range(1, 11): |
5 | multiplications.append(i*n) |
6 | |
7 | print(multiplications) |
8 | # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30] |
Ces boucle imbriquées for
peuvent être ré-écrites de cette façon :
1 | for <element_a> in <iterable_a>: |
2 | for <element_b> in <iterable_b>: |
3 | <the_expression> |
Une fois que la boucle a été éditée sous cette forme, la convertir en liste en compréhension reste aisé :
1 | multiplications = [i*n for i in range(1,4) for n in range(1,11)] |
2 | |
3 | print(multiplications) |
4 | # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30] |
Cette méthode peut être ré-utilisée pour aplatir une liste de listes. La boucle périphérique for
itère à travers chaque liste et les conserve dans la variable row
. La boucle interne for
parcoure tous les éléments de l'état courant de row
. Au cours de la première itération, la variable row
contient les valeurs [1, 2, 3, 4]
. La deuxième boucle explore cette liste ou row
, et ajoute toutes ces valeurs à la liste finale.
1 | matrix = [ |
2 | [1, 2, 3, 4], |
3 | [5, 6, 7, 8], |
4 | [9, 10, 11, 12], |
5 | ] |
6 | |
7 | flatten = [n for row in matrix for n in row] |
8 | |
9 | print(flatten) |
10 | #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] |
Des listes en compréhension imbriquées
Des listes en compréhensions imbriquées pourraient être confondues en listes en compréhension contenant des boucles imbriquées, mais il n'en est rien. Auparavant, vous aviez affaire avec des boucles dans des boucles. Mais dans ce cas précis, vous devrez vous confronter à une liste en compréhension contenant des listes en compréhension. Un bon exemple de ce type serait de créer une transposition de la matrice de la partie précedente.
Sans aucune liste en compréhension, vous aurez besoin de deux boucles for
pour créer la permutation.
1 | matrix = [ |
2 | [1, 2, 3, 4], |
3 | [5, 6, 7, 8], |
4 | [9, 10, 11, 12], |
5 | ] |
6 | |
7 | transpose = [] |
8 | |
9 | for i in range(4): |
10 | temp = [] |
11 | for row in matrix: |
12 | temp.append(row[i]) |
13 | transpose.append(temp) |
14 | |
15 | print(transpose) |
16 | # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] |
La boucle périphérique parcoure la matrice quatre fois puisqu'il y a quatre colonnes à l'intérieur. La boucle interne arpente les éléments de l'état en cours de row, une ligne après l'autre et les ajoute temporairement à la liste déclarée temp
. La liste temp
est alors complétée comme une ligne pour la matrice transposée. Dans le cadre de listes en compréhension, la boucle du plus haut niveau parvient à la fin et celle qui plus basse revient vers le début.
Voici donc le code sous forme d'une liste en compréhension :
1 | matrix = [ |
2 | [1, 2, 3, 4], |
3 | [5, 6, 7, 8], |
4 | [9, 10, 11, 12], |
5 | ] |
6 | |
7 | transpose = [[row[n] for row in matrix] for n in range(4)] |
8 | |
9 | print(transpose) |
10 | # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] |
Il s'agit d'une forme originale, prenant en compte la structure de ces listes, en substituant la classique boucle for
que vous avez appris au début de cet article.
1 | [<the_expression> for <the_element> in <the_iterable>] |
Si vous la comparez avec la liste en compréhension imbriquée ci-dessus, vous noterez que <the_expression>
ici est en fait une autre liste en compréhension : [row[n] for row in matrix]
. Cette seule liste imbriquée est définie sous la forme d'une banale boucle for
.
Dernières réflexions
J'ose imaginer que ce tutoriel aura contribuer à mieux comprendre ce que sont ces listes en compréhension et comment les mettre en œuvre, en lieu et place des boucles for
pour composer un code plus concis et nettement plus performant pour créer des listes.
Autre détail que vous devez garder en tête est la lisibilité de votre code. En rédigeant des listes en compréhension pour des boucles imbriquées va le rendre bien moins compréhensible. Pour contourner ce problème, vous pouvez couper franchement dans cette liste en autant de lignes pour améliorer sa lecture.
Aussi, n'hésitez pas à jeter un œil sur ce qu'il y a à vendre et à étudier sur Envato Market, et n'ayez crainte à poser vos questions et renvoyez vos commentaires en passant par le feed ci-dessous.