les itérateurs permettent de parcourir des données paresseusement. yield crée des générateurs efficaces en mémoire.
objectifs
- utiliser
iter()etnext()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
evens(n)→ générateur des nombres pairs< n.chunks(seq, k)→ générateur de blocs de taille k (dernière fenêtre partielle autorisée).accumulate(seq)→ renvoie la somme cumulée (sans itertools).