Retour au cours

itérateurs et générateurs : iter, next, yield

les itérateurs permettent de parcourir des données paresseusement. yield crée des générateurs efficaces en mémoire.

objectifs

  • utiliser iter() et next() pour comprendre le protocole
  • écrire des générateurs avec yield
  • créer des generator expressions (expr for x in it if ...)
  • produire des flux potentiellement infinis ou coûteux à la demande

explication détaillée

un itérable fournit un itérateur via iter(obj). un itérateur implémente __next__() et renvoie StopIteration en fin. for appelle automatiquement iter(...) puis next(...) en boucle. yield transforme une fonction en générateur : la fonction suspend son état entre deux valeurs.

exemples exécutables

# protocole à nu
it = iter([10, 20, 30])
print(next(it))
print(next(it))
print(next(it))
# next(it) -> StopIteration
# générateur simple
def count_up(n):
    i = 0
    while i < n:
        yield i
        i += 1

for x in count_up(3):
    print(x)
# generator expression
total = sum(n*n for n in range(1, 6))
print(total)  # 55
# pipeline paresseux
def evens():
    n = 0
    while True:
        yield n
        n += 2

for x in (n for n in evens() if n <= 6):
    print(x)   # 0 2 4 6
# fenêtres glissantes de taille k
from collections import deque
def windows(seq, k):
    it = iter(seq)
    q = deque(maxlen=k)
    for x in it:
        q.append(x)
        if len(q) == k:
            yield tuple(q)

print(list(windows(range(6), 3)))

bonnes pratiques

  • préférez un générateur si la taille est grande ou inconnue
  • composez des générateurs (pipes) pour éviter des listes intermédiaires
  • documentez bien les générateurs potentiellement infinis

pièges courants

  • épuiser un itérateur puis tenter de le réutiliser
  • confondre itérable et itérateur
  • consommer un générateur deux fois (il faut en créer un nouveau)

exercices

  1. evens(n) → générateur des nombres pairs < n.
  2. chunks(seq, k) → générateur de blocs de taille k (dernière fenêtre partielle autorisée).
  3. accumulate(seq) → renvoie la somme cumulée (sans itertools).