CodeGym /Cours /Python SELF FR /Générateurs

Générateurs

Python SELF FR
Niveau 13 , Leçon 4
Disponible

3.1 Introduction aux générateurs

Les générateurs sont des fonctions qui retournent un objet itérateur. Ces itérateurs génèrent des valeurs à la demande, ce qui permet de gérer potentiellement de grandes quantités de données sans les charger entièrement en mémoire.

Il existe plusieurs façons de créer des générateurs, et nous verrons ci-dessous les plus populaires.

Générateurs basés sur les fonctions

Les générateurs sont créés en utilisant le mot-clé yield à l'intérieur d'une fonction. Lorsque la fonction avec yield est appelée, elle retourne un objet générateur, mais n'exécute pas immédiatement le code à l'intérieur de la fonction. Au lieu de cela, l'exécution est suspendue à l'expression yield et reprend à chaque appel de la méthode __next__() de l'objet générateur.


def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1
        
counter = count_up_to(5)
print(next(counter))  # Sortie: 1
print(next(counter))  # Sortie: 2
print(next(counter))  # Sortie: 3
print(next(counter))  # Sortie: 4
print(next(counter))  # Sortie: 5

Si une fonction contient une instruction yield, Python crée un objet générateur qui gère l'état d'exécution de la fonction au lieu de l'exécuter traditionnellement.

Expressions génératrices

Les expressions génératrices ressemblent aux List Comprehensions, mais sont créées en utilisant des parenthèses au lieu de crochets. Elles retournent également un objet générateur.


squares = (x ** 2 for x in range(10))

print(next(squares))  # Sortie: 0
print(next(squares))  # Sortie: 1
print(next(squares))  # Sortie: 4

Lequel de ces moyens préfères-tu ?

3.2 Les avantages des générateurs

Utilisation efficace de la mémoire

Les générateurs calculent les valeurs à la volée, ce qui permet de traiter de grandes quantités de données sans les charger entièrement en mémoire. Cela rend les générateurs idéaux pour travailler avec de grands ensembles de données ou des flux de données.


def large_range(n):
    for i in range(n):
        yield i
        
for value in large_range(1000000):
    # Traiter les valeurs une par une
    print(value)

Calculs paresseux

Les générateurs effectuent des calculs paresseux, ce qui signifie qu'ils calculent les valeurs uniquement lorsqu'elles sont nécessaires. Cela permet d'éviter des calculs inutiles et d'améliorer les performances.


def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b
        
fib = fibonacci()
for _ in range(10):
    print(next(fib))

Simplicité syntaxique

Les générateurs offrent une syntaxe pratique pour créer des itérateurs, ce qui simplifie l'écriture et la lecture du code.

3.3 Utilisation des générateurs

Exemples d'utilisation des générateurs dans la bibliothèque standard

De nombreuses fonctions dans la bibliothèque standard de Python utilisent des générateurs. Par exemple, la fonction range() retourne un objet générateur qui génère une séquence de nombres.


for i in range(10):
    print(i)

Oui, le monde ne sera plus jamais le même.

Création de séquences infinies

Les générateurs permettent de créer des séquences infinies, utiles dans divers scénarios tels que la génération de flux de données infinis.


def natural_numbers():
    n = 1
    while True:
        yield n
        n += 1
        
naturals = natural_numbers()
for _ in range(10):
    print(next(naturals))

Utilisation de send() et close()

Les objets générateurs supportent les méthodes send() et close(), qui permettent d'envoyer des valeurs à un générateur et de terminer son exécution.


def echo():
    while True:
        received = yield
        print(received)
        
e = echo()
next(e)  # Lancer le générateur
e.send("Hello, world!")  # Sortie: Hello, world!
e.close()

3.4 Générateurs en pratique

Générateurs et exceptions

Les générateurs peuvent gérer les exceptions, ce qui en fait un outil puissant pour écrire du code plus robuste.


def controlled_execution():
    try:
        yield "Start"
        yield "Working"
    except GeneratorExit:
        print("Generator closed")
        
gen = controlled_execution()
print(next(gen))  # Sortie: Start
print(next(gen))  # Sortie: Working
gen.close()  # Sortie: Generator closed

Nous verrons comment gérer les exceptions dans les prochains cours, mais je pense que ce serait utile de savoir que les générateurs fonctionnent bien avec elles.

Générateurs imbriqués

Les générateurs peuvent être imbriqués, ce qui permet de créer des structures itératives complexes.


def generator1():
    yield from range(3)
    yield from "ABC"
        
for value in generator1():
    print(value)

# Sortie
0
1
2
A
B
C

Explication :

yield from : Cette construction est utilisée pour déléguer une partie des opérations à un autre générateur, ce qui permet de simplifier le code et d'améliorer la lisibilité.

Générateurs et performance

L'utilisation de générateurs peut considérablement améliorer la performance des programmes en réduisant l'utilisation de la mémoire et en rendant les itérations plus efficaces.

Exemple de comparaison entre listes et générateurs


import time
import sys

def memory_usage(obj):
    return sys.getsizeof(obj)

n = 10_000_000

# Utilisation d'une liste
start_time = time.time()
list_comp = [x ** 2 for x in range(n)]
list_time = time.time() - start_time
list_memory = memory_usage(list_comp)

# Utilisation d'un générateur
start_time = time.time()
gen_comp = (x ** 2 for x in range(n))
gen_result = sum(gen_comp)  # Calculer la somme pour comparer les résultats
gen_time = time.time() - start_time
gen_memory = memory_usage(gen_comp)

print(f"Liste:")
print(f"  Temps: {list_time:.2f} sec")
print(f"  Mémoire: {list_memory:,} octets")

print(f"\nGénérateur:")
print(f"  Temps: {gen_time:.2f} sec")
print(f"  Mémoire: {gen_memory:,} octets")

Liste:
  Temps: 0.62 sec
  Mémoire: 89,095,160 octets

Générateur:
  Temps: 1.13 sec
  Mémoire: 200 octets
1
Étude/Quiz
Fonctions système, niveau 13, leçon 4
Indisponible
Fonctions système
Fonctions système
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION