Les calculs « à la demande » ou les calculs paresseux ont gagné en popularité avec l'augmentation des volumes de données traitées. En Python, ces mécanismes ont été implémentés dans la bibliothèque standard via des générateurs et des itérateurs, plus tard — à travers la fonction itertools et des classes capables de retourner un élément à la fois sur demande, évitant ainsi de stocker toutes les données en mémoire en même temps.
La construction ordinaire de collections nécessite de charger en mémoire l'ensemble du résultat. Si le volume est important, le programme peut « planter » ou fonctionner très lentement. Il est essentiel de savoir traiter les flux de données — par exemple, des fichiers de plusieurs giga-octets ou les résultats d’appels API.
Les calculs paresseux permettent d'obtenir des éléments au fur et à mesure des besoins. En Python, cela est facilité par l'utilisation de générateurs, de la syntaxe yield, des expressions génératrices, des fonctions map, filter, zip, ainsi que du module itertools. Cette approche repose sur le protocole des itérateurs.
Exemple de code:
def huge_sequence(): for i in range(1, 10**9): yield i * i for val in huge_sequence(): if val > 100: break print(val)
Caractéristiques clés:
Les générateurs en Python économisent-ils toujours de la mémoire?
Réponse: Non, seulement si les données ne nécessitent réellement pas de stockage intermédiaire entre les étapes. Certaines constructions, comme les compréhensions de listes, créent l'ensemble de la liste à la fois, tandis que les générateurs ne le font que sur demande. Si les résultats intermédiaires sont néanmoins requis, les économies sont perdues.
Exemple:
squares = (x**2 for x in range(10**8)) # paresseux, économique result = list(squares) # consomme immédiatement toute la mémoire
Est-il vrai que map et filter retournent toujours des listes?
Non, en Python 3, map et filter ne retournent pas une liste, mais un itérateur (générateur paresseux), ce qui économise de la mémoire et permet de traiter les données « à la volée ».
Peut-on itérer plusieurs fois sur un générateur?
Non, un générateur « s'épuise » après un parcours complet. Si un parcours répété est nécessaire, il vaut mieux créer un nouveau générateur ou utiliser une collection de conteneurs dont le contenu peut être parcouru plusieurs fois.
Un développeur essaie de traiter un gros fichier log en le chargeant en mémoire sous forme de liste de chaînes.
Avantages:
Inconvénients:
Un générateur est utilisé — lecture ligne par ligne du fichier avec traitement de chaque ligne au fur et à mesure.
Avantages:
Inconvénients: