Générateurs Python : du concept fondamental à itertools

  1. Introduction aux générateurs

Un générateur est une fonction qui utilice le mot-clé yield au lieu de return. Contrairement à une fonction classique, l'exécution s'arrête à chaque yield et reprend lors de l'appel suivant à next().

Exemple simple :

def generateur_simple():
    yield "premier"
    yield "second"
    yield "troisième"

g = generateur_simple()
print(next(g))  # premier
print(next(g))  # second
print(next(g))  # troisième

Dans la pratique, on utilise rarmeent next() directement. La boucle for est plus naturelle et appelle automatiquement next() derrière le rideau :

for valeur in generateur_simple():
    print(valeur)

Les générateurs évitent les calculs inutiles et économisent la mémoire. Ils permettent même de représenter des séquences infinies, ce qui est impossible avec une list classique.

  1. Itérables et itérateurs

En Python, tout objet utilisable dans une boucle for est un itérable (Iterable). Cela inclut :

  • Les types de données de collection : listes, tuples, dictionnaires, ensembles, chaînes
  • Les générateurs

On peut vérifier avec isinstance() :

from collections.abc import Iterable

print(isinstance([], Iterable))       # True
print(isinstance({}, Iterable))       # True
print(isinstance("abc", Iterable))    # True
print(isinstance((x for x in range(10)), Iterable))  # True
print(isinstance(100, Iterable))      # False

Un itérateur (Iterator) est un flux de données. On peut lui appliquer next() pour obtenir l'élément suivant, jusqu'à ce que StopIteration soit levé. Les générateurs sont des itérateurs, mais les listes, dictionnaires ou chaînes ne le sont pas.

Pour transformer un itérable en itérateur, on utilise iter() :

from collections.abc import Iterator

print(isinstance(iter([]), Iterator))      # True
print(isinstance(iter("abc"), Iterator))   # True

Sous le capot, une boucle for en Python équivaut à :

# Transformation implicite
collection = [1, 2, 3, 4, 5]
it = iter(collection)

while True:
    try:
        element = next(it)
        # traitement
    except StopIteration:
        break

  1. Le module itertools

Le module standard itertools propose des fonctions puissantes pour manipuler les itérateurs. Voici un exemple avec islice :

from itertools import islice

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

gen_fibo = fibonacci()
dix_premiers = list(islice(gen_fibo, 10))
print(dix_premiers)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

islice(iterable, stop) crée un itérateur qui produit les stop premiers éléments de iterable, sans consommer toute la séquence en mémoire. Cela fonctionne aussi avec des paramètres de début et de pas : islice(iterable, start, stop, step).

Étiquettes: Python générateurs yield Iterable Iterator

Publié le 16 juillet à 18h09