
Expressions génératrices
Découvrez les expressions génératrices en Python, une syntaxe concise pour créer des itérateurs. Similaires aux compréhensions de listes, mais avec une évaluation paresseuse, elles sont idéales pour les grandes séquences.
Qu'est-ce qu'une expression génératrice ? Syntaxe et comparaison avec les compréhensions de listes
Une expression génératrice est une expression concise qui permet de créer un itérateur en Python. Elle est similaire à une compréhension de liste, mais au lieu de créer une liste en mémoire, elle crée un générateur (un type d'itérateur) qui produit les éléments à la demande (évaluation paresseuse).
La syntaxe d'une expression génératrice est très proche de celle d'une compréhension de liste, mais elle utilise des parenthèses `()` au lieu de crochets `[]`.
Syntaxe :
(expression for item in iterable if condition)- `expression` : Une expression qui est évaluée pour chaque `item` de l'`iterable`.
- `item` : Une variable qui prend successivement la valeur de chaque élément de l'`iterable`.
- `iterable` : Une séquence (liste, tuple, chaîne de caractères, etc.) ou un itérable.
- `condition` (optionnelle) : Une condition qui filtre les éléments de l'iterable`.
Exemple : Une expression génératrice qui produit les carrés des nombres de 0 à 9
carres = (x**2 for x in range(10)) # Expression génératrice
print(carres) # at ...>
for carre in carres:
print(carre) # 0 1 4 9 16 25 36 49 64 81 Dans cet exemple, `(x**2 for x in range(10))` est une expression génératrice. Elle crée un objet générateur, mais elle ne calcule pas immédiatement les carrés. Les carrés sont calculés un par un, au fur et à mesure que la boucle `for` les demande.
Comparaison avec une compréhension de liste :
# Compréhension de liste (crée une liste en mémoire)
carres_liste = [x**2 for x in range(10)]
# Expression génératrice (crée un itérateur)
carres_generateur = (x**2 for x in range(10))La principale différence est que la compréhension de liste crée immédiatement une liste contenant tous les résultats, tandis que l'expression génératrice crée un itérateur qui produit les résultats à la demande.
Avantages des expressions génératrices : évaluation paresseuse et efficacité mémoire
Les expressions génératrices présentent les mêmes avantages que les générateurs créés avec le mot-clé `yield` :
- Evaluation paresseuse (lazy evaluation) : Les éléments ne sont calculés qu'au moment où ils sont nécessaires.
- Efficacité mémoire : Les expressions génératrices ne stockent pas tous les éléments en mémoire en même temps. Elles sont donc particulièrement adaptées pour traiter de grandes séquences de données ou des séquences infinies.
Exemple (comparaison de l'utilisation mémoire) :
import sys
# Compréhension de liste (crée une grande liste en mémoire)
grosse_liste = [x for x in range(1000000)]
print("Taille de la liste :", sys.getsizeof(grosse_liste), "octets")
# Expression génératrice (crée un itérateur)
gros_generateur = (x for x in range(1000000))
print("Taille du générateur :", sys.getsizeof(gros_generateur), "octets")Vous constaterez que la taille de l'objet générateur est beaucoup plus petite que la taille de la liste, car le générateur ne stocke pas tous les éléments en mémoire.
Cas d'utilisation des expressions génératrices
Les expressions génératrices sont particulièrement utiles dans les cas suivants :
- Traitement de grandes séquences de données : Lorsque vous devez traiter une grande quantité de données qui ne tiendrait pas en mémoire si vous utilisiez une liste.
- Séquences infinies : Lorsque vous devez travailler avec une séquence potentiellement infinie (par exemple, un flux de données).
- Combinaison avec d'autres fonctions : Lorsque vous devez passer un itérateur à une autre fonction (comme `sum`, `min`, `max`, `any`, `all`, `map`, `filter`, etc.).
- Simplification du code : Lorsque vous voulez créer un itérateur simple sans avoir à définir une fonction génératrice complète avec `yield`.
Exemples :
# Somme des carrés des nombres de 0 à 999999 (sans créer de liste intermédiaire)
somme_carres = sum(x**2 for x in range(1000000))
# Vérifier si une liste contient au moins un nombre pair
nombres = [1, 3, 5, 7, 8, 9]
contient_pair = any(x % 2 == 0 for x in nombres)
# Trouver le plus grand nombre pair d'une liste
nombres = [1, 3, 8, 5, 2, 6]
plus_grand_pair = max((x for x in nombres if x % 2 == 0), default=None)Expressions génératrices vs. compréhensions de listes : quand utiliser l'une ou l'autre ?
Le choix entre une expression génératrice et une compréhension de liste dépend du contexte :
- Compréhension de liste : Utilisez-la lorsque vous avez besoin d'une liste complète en mémoire, par exemple si vous devez accéder plusieurs fois aux éléments, ou si vous devez utiliser des méthodes de liste (comme `append`, `insert`, `sort`, etc.).
- Expression génératrice : Utilisez-la lorsque vous n'avez besoin d'accéder aux éléments qu'une seule fois, ou lorsque vous travaillez avec de très grandes séquences ou des séquences infinies, ou lorsque vous passez l'itérateur directement à une autre fonction.
En général, si vous n'êtes pas sûr, commencez par une compréhension de liste. Si vous constatez des problèmes de performance ou de mémoire, vous pourrez toujours la remplacer par une expression génératrice.
Il est également important de noter que vous pouvez imbriquer des expressions génératrices et des compréhensions de listes/dictionnaires/ensembles.