En Python, il est simple d'utiliser la notation de compréhension de liste lors de la génération d'une nouvelle liste.(List comprehensions
)
- 5. Data Structures — List Comprehensions — Python 3.10.0 Documentation
- 6. Expressions — Displays for lists, sets and dictionaries — Python 3.10.0 Documentation
Dans cet article, nous allons d'abord aborder les points suivants
- Type de notation de base pour la compréhension des listes
- Notation de compréhension de liste avec branchement conditionnel par if
- Combinaison avec des opérateurs ternaires (traitement de type if else)
zip()
,enumerate()
Combinaison avec ces derniers- notation d'inclusion de listes imbriquées
Ensuite, nous expliquerons l'ensemble de la notation de la compréhension des listes à l'aide d'un exemple de code.
- notation d'inclusion d'ensemble(
Set comprehensions
) - notation d'inclusion de dictionnaire(
Dict comprehensions
) - type de générateur(
Generator expressions
)
- Type de notation de base pour la compréhension des listes
- Notation de compréhension de liste avec branchement conditionnel par if
- Combinaison avec des opérateurs ternaires (traitement de type if else)
- Combinaison avec zip() et enumerate()
- notation d'inclusion de listes imbriquées
- notation d'inclusion d'ensemble(Set comprehensions)
- notation d'inclusion de dictionnaire(Dict comprehensions)
- type de générateur(Generator expressions)
Type de notation de base pour la compréhension des listes
La notation de compréhension de liste s'écrit comme suit.
[Expression for Any Variable Name in Iterable Object]
Elle prend chaque élément d'un objet itérable tel qu'une liste, un tuple ou une plage par un nom de variable arbitraire et l'évalue avec une expression. Une nouvelle liste avec le résultat de l'évaluation comme élément est retournée.
Un exemple est donné, ainsi qu'une déclaration for équivalente.
squares = [i**2 for i in range(5)]
print(squares)
# [0, 1, 4, 9, 16]
squares = []
for i in range(5):
squares.append(i**2)
print(squares)
# [0, 1, 4, 9, 16]
Le même processus peut être effectué avec map(), mais la notation de compréhension de liste est préférée pour sa simplicité et sa clarté.
Notation de compréhension de liste avec branchement conditionnel par if
Le branchement conditionnel avec if est également possible. Écrivez le if dans le postfixe comme suit.
[Expression for Any Variable Name in Iterable Object if Conditional Expression]
Seuls les éléments de l'objet itérable dont l'expression conditionnelle est vraie sont évalués par l'expression, et une nouvelle liste dont les éléments sont le résultat est retournée.
Vous pouvez utiliser n'importe quel nom de variable dans l'expression conditionnelle.
Un exemple est donné, ainsi qu'une déclaration for équivalente.
odds = [i for i in range(10) if i % 2 == 1]
print(odds)
# [1, 3, 5, 7, 9]
odds = []
for i in range(10):
if i % 2 == 1:
odds.append(i)
print(odds)
# [1, 3, 5, 7, 9]
Le même processus peut être effectué avec filter(), mais la notation de compréhension de liste est préférée pour sa simplicité et sa clarté.
Combinaison avec des opérateurs ternaires (traitement de type if else)
Dans l'exemple ci-dessus, seuls les éléments qui répondent aux critères sont traités, et ceux qui ne répondent pas aux critères sont exclus de la nouvelle liste.
Si vous voulez changer le processus en fonction de la condition, ou si vous voulez traiter différemment les éléments qui ne satisfont pas à la condition, comme dans if else, utilisez l'opérateur ternaire.
En Python, l'opérateur ternaire peut être écrit comme suit
Value When True if Conditional Expression else Value When False
Elle est utilisée dans la partie expression de la notation de compréhension de la liste, comme indiqué ci-dessous.
[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]
Un exemple est donné, ainsi qu'une déclaration for équivalente.
odd_even = ['odd' if i % 2 == 1 else 'even' for i in range(10)]
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
odd_even = []
for i in range(10):
if i % 2 == 1:
odd_even.append('odd')
else:
odd_even.append('even')
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
Il est également possible d'écrire des expressions en utilisant des noms de variables arbitraires pour les valeurs vrai et faux.
Si la condition est satisfaite, un traitement est effectué, sinon la valeur de l'objet itérable original est laissée inchangée.
odd10 = [i * 10 if i % 2 == 1 else i for i in range(10)]
print(odd10)
# [0, 10, 2, 30, 4, 50, 6, 70, 8, 90]
Combinaison avec zip() et enumerate()
Les fonctions utiles qui sont souvent utilisées dans l'instruction for comprennent zip(), qui combine plusieurs itérables, et enumerate(), qui renvoie une valeur avec son index.
Bien sûr, il est possible d'utiliser zip() et enumerate() avec la notation de compréhension de liste. Ce n'est pas une syntaxe spéciale, et ce n'est pas difficile si l'on considère la correspondance avec l'instruction for.
Exemple de zip().
l_str1 = ['a', 'b', 'c']
l_str2 = ['x', 'y', 'z']
l_zip = [(s1, s2) for s1, s2 in zip(l_str1, l_str2)]
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
l_zip = []
for s1, s2 in zip(l_str1, l_str2):
l_zip.append((s1, s2))
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
Exemple d'enumerate().
l_enu = [(i, s) for i, s in enumerate(l_str1)]
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
l_enu = []
for i, s in enumerate(l_str1):
l_enu.append((i, s))
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
L'idée est la même que pour l'utilisation de if.
l_zip_if = [(s1, s2) for s1, s2 in zip(l_str1, l_str2) if s1 != 'b']
print(l_zip_if)
# [('a', 'x'), ('c', 'z')]
Chaque élément peut également être utilisé pour calculer un nouvel élément.
l_int1 = [1, 2, 3]
l_int2 = [10, 20, 30]
l_sub = [i2 - i1 for i1, i2 in zip(l_int1, l_int2)]
print(l_sub)
# [9, 18, 27]
notation d'inclusion de listes imbriquées
Tout comme les boucles for imbriquées, la notation de compréhension de liste peut également être imbriquée.
[Expression for Variable Name 1 in Iterable Object 1
for Variable Name 2 in Iterable Object 2
for Variable Name 3 in Iterable Object 3 ... ]
Pour des raisons de commodité, des sauts de ligne et des indentations ont été ajoutés, mais ne sont pas nécessaires pour la grammaire ; ils peuvent être poursuivis sur une seule ligne.
Un exemple est donné, ainsi qu'une déclaration for équivalente.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
flat = []
for row in matrix:
for x in row:
flat.append(x)
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Il est également possible d'utiliser plusieurs variables.
cells = [(row, col) for row in range(3) for col in range(2)]
print(cells)
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
Vous pouvez également effectuer un branchement conditionnel.
cells = [(row, col) for row in range(3)
for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]
Il est également possible d'effectuer un branchement conditionnel pour chaque objet itérable.
cells = [(row, col) for row in range(3) if row % 2 == 0
for col in range(2) if col % 2 == 0]
print(cells)
# [(0, 0), (2, 0)]
notation d'inclusion d'ensemble(Set comprehensions)
En remplaçant les crochets [] de la notation de compréhension de liste par des accolades {}, on crée un ensemble (objet de type ensemble).
{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}
print(s)
# {0, 1, 4, 9, 16}
notation d'inclusion de dictionnaire(Dict comprehensions)
Les dictionnaires (objets de type dict) peuvent également être générés avec la notation de compréhension.
{}, et spécifiez la clé et la valeur dans la partie expression comme clé : valeur.
{Key: Value for Any Variable Name in Iterable Object}
Toute expression peut être spécifiée pour la clé et la valeur.
l = ['Alice', 'Bob', 'Charlie']
d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}
Pour créer un nouveau dictionnaire à partir d'une liste de clés et de valeurs, utilisez la fonction zip().
keys = ['k1', 'k2', 'k3']
values = [1, 2, 3]
d = {k: v for k, v in zip(keys, values)}
print(d)
# {'k1': 1, 'k2': 2, 'k3': 3}
type de générateur(Generator expressions)
Si les crochets [] de la notation de compréhension de liste sont utilisés comme des crochets ronds (), un générateur est renvoyé au lieu d'un tuple. C'est ce qu'on appelle les expressions de générateur.
Exemple de notation de compréhension de liste.
l = [i**2 for i in range(5)]
print(l)
# [0, 1, 4, 9, 16]
print(type(l))
# <class 'list'>
Exemple d'une expression de générateur. Si vous imprimez() le générateur tel qu'il est, il n'imprimera pas son contenu, mais si vous l'exécutez avec une instruction for, vous pouvez obtenir le contenu.
g = (i**2 for i in range(5))
print(g)
# <generator object <genexpr> at 0x10af944f8>
print(type(g))
# <class 'generator'>
for i in g:
print(i)
# 0
# 1
# 4
# 9
# 16
Les expressions génératrices permettent également le branchement conditionnel et l'imbrication en utilisant la notation if ainsi que la notation de compréhension de liste.
g_cells = ((row, col) for row in range(0, 3)
for col in range(0, 2) if col == row)
print(type(g_cells))
# <class 'generator'>
for i in g_cells:
print(i)
# (0, 0)
# (1, 1)
Par exemple, si une liste comportant un grand nombre d'éléments est générée à l'aide de la notation de compréhension de liste, puis parcourue en boucle avec une instruction for, la liste contenant tous les éléments sera générée au début si la notation de compréhension de liste est utilisée. En revanche, si vous utilisez une expression de générateur, chaque fois que la boucle est répétée, les éléments sont générés un par un, ce qui réduit la quantité de mémoire utilisée.
Si l'expression du générateur est le seul argument de la fonction, les parenthèses rondes () peuvent être omises.
print(sum([i**2 for i in range(5)]))
# 30
print(sum((i**2 for i in range(5))))
# 30
print(sum(i**2 for i in range(5)))
# 30
Quant à la vitesse de traitement, la notation de compréhension de liste est souvent plus rapide que la notation de générateur lorsque tous les éléments sont traités.
Toutefois, lors d'un jugement avec all() ou any(), par exemple, le résultat est déterminé en fonction de la présence de false ou de true, de sorte que l'utilisation d'expressions de générateur peut être plus rapide que l'utilisation de la notation de compréhension de liste.
Il n'existe pas de notation de compréhension des tuple, mais si vous utilisez une expression de générateur comme argument de tuple(), vous pouvez générer un tuple dans la notation de compréhension.
t = tuple(i**2 for i in range(5))
print(t)
# (0, 1, 4, 9, 16)
print(type(t))
# <class 'tuple'>