ProgrammationDéveloppeur Python

Expliquez ce que sont les générateurs en Python. Comment ils fonctionnent, à quoi ils servent et en quoi ils diffèrent des expressions de liste ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Les générateurs sont des objets itérables spéciaux en Python qui permettent de créer des séquences "à la volée", sans occuper de mémoire pour toute la collection en même temps. Ils sont implémentés à l'aide de fonctions avec le mot-clé yield ou d'expressions génératrices ((expr for ... in ...)). C'est pratique lors du traitement de grandes quantités de données ou de flux potentiellement infinis.

Différences clés par rapport aux expressions de liste :

  • Expressions de liste ([x for x in range(10)]) créent immédiatement toute la liste en mémoire.
  • Générateurs ((x for x in range(10))) créent les éléments un par un, consommant beaucoup moins de mémoire.

Quand utiliser des générateurs :

  • Si l'accès aux éléments par index n'est pas nécessaire.
  • Si les données sont trop volumineuses pour être stockées en mémoire.
  • Lors de l'organisation d'un traitement des données en streaming (par exemple, lire des lignes d'un fichier).
# Fonction génératrice def counter(n): for i in range(n): yield i for number in counter(5): print(number)

Question piège.

"Quelle est la différence entre l'utilisation d'une fonction avec yield et une fonction ordinaire qui retourne une liste ? Donnez un exemple."

Réponse : Une fonction ordinaire calcule et retourne immédiatement une liste, occupant ainsi de la mémoire pour tous ses éléments. Une fonction avec yield retourne un générateur, qui produit les éléments un par un sans charger toute la séquence en mémoire à la fois.

def make_list(n): return [i for i in range(n)] # Retourne immédiatement une liste, utilise beaucoup de mémoire def make_generator(n): for i in range(n): yield i # Produira un élément à la fois

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


Histoire

Dans un projet d'analyse de grands journaux, des expressions de liste ont été utilisées pour extraire des lignes contenant des erreurs :

error_lines = [line for line in open('biglog.txt') if 'ERROR' in line]

Le fichier dépassait 2 Go et l'application a échoué avec OOM (Out of Memory). Il fallait utiliser un générateur :

error_lines = (line for line in open('biglog.txt') if 'ERROR' in line)

Histoire

Un employé voulait analyser une courte liste, écrit une fonction avec yield, mais a oublié que ce qui est retourné est un générateur et non une liste :

result = my_generator_function() # result — générateur, pas liste if len(result) > 5: # TypeError: objet de type 'generator' n'a pas de len()

Correction : envelopper le résultat dans list().


Histoire

Ils ont essayé d'itérer sur un générateur plusieurs fois :

numbers = (i for i in range(5)) for n in numbers: pass # épuisé le générateur for n in numbers: print(n) # ne produit rien

Un générateur est à usage unique. Il faut en créer un nouveau pour une réutilisation.