Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🐍
Avance 20 min Python

Les generateurs Python

Pourquoi generateurs Python ?

Dans un monde où les données s'accroissent à une vitesse exponentielle, la gestion efficace de ces ressources est cruciale pour les développeurs. Les générateurs en Python offrent une solution élégante et performante pour gérer des séquences de données volumineuses ou infinies sans nécessiter le stockage de tout le contenu en mémoire à la fois. Ils sont particulièrement utiles dans les applications suivantes :

  1. Traitement de grandes quantités de données : Imaginez une situation où vous devez traiter des milliards de lignes de données provenant d'un fichier CSV ou d'une base de données. Utiliser un générateur permettrait de lire et de traiter chaque ligne individuellement sans charger tout le contenu en mémoire.
  2. Gestion d'APIs et de flux de données : Les APIs modernes oftenent des émissions de données en continu, par exemple les API de streaming vidéo ou de musique. Les générateurs peuvent être utilisés pour itérer sur ces flux de données, un élément à la fois, sans avoir besoin de stocker tous les éléments simultanément.

Prerequis

Avant de plonger dans le sujet des générateurs Python, il est important d'avoir une certaine compréhension des concepts suivants :

  • Connaissances en programmation orientée objet (POO) : Comprendre les classes et les objets est crucial pour utiliser les générateurs.
  • Expérience avec les boucles for et les itérables : C'est le fondement de la compréhension des générateurs.

Les outils suivants doivent être installés sur votre environnement de développement :

  • Python 3.6 ou plus récent
  • Un éditeur de code (ex: Visual Studio Code, PyCharm)

Concepts fondamentaux

1. Compréhension du concept de générateur

Un générateur est un type spécial d'itérable qui ne stocke pas tous ses éléments en mémoire à la fois. Au lieu de cela, il génère les éléments un par un à mesure qu'ils sont demandés. Cette caractéristique rend les générateurs particulièrement efficaces pour gérer des séquences de données volumineuses.

Schéma mental :

+-------------------+
| Générateur        |
|                   |
| - Méthode __iter__()|
|   (renvoie l'objet)|
| - Méthode __next__()|
|   (génère le prochain élément)|
+-------------------+
| Élément 1         | <---- Généré et retourné au premier appel à next()
+-------------------+
| Élément 2         | <---- Généré et retourné au deuxième appel à next()
+-------------------+
| ...               |
+-------------------+

Code fonctionnel :

def generate_numbers(n):
    for i in range(n):
        yield i
## 
gen = generate_numbers(5)
print(next(gen))  # Sortie : 0
print(next(gen))  # Sortie : 1

2. Création de générateurs avec des expressions génératrices

Les expressions génératrices offrent une syntaxe concise pour créer des générateurs. Elles ressemblent aux listes compréhensions, mais utilisent des parenthèses plutôt que des crochets.

Schéma mental :

+-------------------+
| Expression        |
| Génératrice       |
|                   |
| (x for x in range(n))|
+-------------------+

Code fonctionnel :

gen = (x * 2 for x in range(5))
## 
for number in gen:
    print(number)  # Sortie : 0, 2, 4, 6, 8

3. Compréhension de la différence entre un itérable et un itérateur

  • Itérable : Un objet qui peut être itéré sur en utilisant une boucle for ou la fonction iter(). Les itérables ont une méthode __iter__().

    # Exemple d'un itérable
    my_list = [1, 2, 3]
    
  • Itérateur : Un objet qui peut fournir les éléments successifs d'un itérable en utilisant la méthode __next__(). Les itérateurs ont une méthode __iter__() et une méthode __next__().

    # Exemple d'un itérateur
    my_list = [1, 2, 3]
    my_iter = iter(my_list)
    

4. Utilisation de la fonction yield from

La fonction yield from permet de déléguer l'itération à un autre générateur ou itérateur. Cela peut rendre le code plus clair et réutilisable.

Schéma mental :

+-------------------+
| Générateur        |
|                   |
| yield from gen    |
+-------------------+

Code fonctionnel :

def sub_generator():
    yield 1
    yield 2

def main_generator():
    yield from sub_generator()
    yield 3
## 
for number in main_generator():
    print(number)  # Sortie : 1, 2, 3

Mise en pratique : projet fil rouge

Nous allons créer un mini-projet simple qui utilise les générateurs pour gérer une liste de tâches. Ce projet comprendra les fonctionnalités suivantes :

  1. Ajout d'une nouvelle tâche.
  2. Affichage de toutes les tâches.
  3. Suppression d'une tâche.

Étape 1 : Création du fichier task_manager.py


class TaskManager:
    def __init__(self):
        self.tasks = []

    def add_task(self, task):
        self.tasks.append(task)

    def get_tasks(self):
        return self.tasks

    def remove_task(self, task):
        if task in self.tasks:
            self.tasks.remove(task)

Étape 2 : Création du fichier task_generator.py


def generate_tasks(manager):
    for task in manager.get_tasks():
        yield task

Étape 3 : Création du fichier main.py


from task_manager import TaskManager
from task_generator import generate_tasks

def main():
    manager = TaskManager()

    # Ajout de tâches
    manager.add_task("Faire les courses")
    manager.add_task("Nettoyer la chambre")
    manager.add_task("Réviser Python")

    # Affichage des tâches
    print("Liste des tâches :")
    for task in generate_tasks(manager):
        print(task)

    # Suppression d'une tâche
    manager.remove_task("Faire les courses")

    # Affichage des tâches mise à jour
    print("\nListe des tâches mis à jour :")
    for task in generate_tasks(manager):
        print(task)

if __name__ == "__main__":
    main()

Étape 4 : Exécution du projet

python main.py

Sortie attendue :

Liste des tâches :
Faire les courses
Nettoyer la chambre
Réviser Python

Liste des tâches mis à jour :
Nettoyer la chambre
Réviser Python

Erreurs frequentes et debugging

1. StopIteration exception

Code incorrect :

gen = (x for x in range(5))
next(gen)
next(gen)
next(gen)
next(gen)
next(gen)  # Provoque une exception StopIteration

Code correct :

gen = (x for x in range(5))
for _ in range(5):
    print(next(gen))  # Affiche les nombres de 0 à 4 sans exception

2. Générateur fermé

Code incorrect :

gen = (x * 2 for x in range(5))
next(gen)
del gen  # Le générateur est supprimé, mais il peut toujours être utilisé
print(next(gen))  # Provoque une exception ValueError

Code correct :

with (x * 2 for x in range(5)) as gen:
    print(next(gen))  # Affiche le premier élément du générateur
## 
print(next(gen))  # Provoque une exception StopIteration

3. Générateur non itérable

Code incorrect :

gen = (x * 2 for x in range(5))
for _ in gen:
    pass
## 
print(next(gen))  # Provoque une exception StopIteration

Code correct :

gen = (x * 2 for x in range(5))
for _ in gen:
    pass
## 
new_gen = (x * 2 for x in range(5))
print(next(new_gen))  # Affiche le premier élément du nouveau générateur

Pour aller plus loin

1. Générateurs et fonctions génératrices asynchrones

Les fonctions génératrices asynchrones (async generators) permettent de traiter des flux de données asynchrones de manière efficace.

2. Utilisation de itertools pour créer des générateurs

Le module itertools fournit une variété de fonctions utilitaires pour travailler avec les itérables et les générateurs.

3. Compréhension des co-routines

Les co-routines en Python permettent de créer des applications asynchrones performantes et évolutives.

Défi pratique

Créez un générateur qui lit les lignes d'un fichier CSV et les retourne une par une. Assurez-vous que le fichier est fermé correctement après l'itération.

Fichier file_reader.py :

import csv

def read_csv(filename):
    with open(filename, newline='') as csvfile:
        reader = csv.reader(csvfile)
        for row in reader:
            yield row

Utilisation dans main.py :

from file_reader import read_csv

filename = "data.csv"
for row in read_csv(filename):
    print(row)

Ce défi vous permettra d'appliquer les concepts appris sur la gestion des ressources et la création de générateurs dans un contexte réel.

Besoin d'aide sur Python ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Qu'est-ce qu'un générateur en Python?
Un générateur en Python est une fonction qui utilise le mot-clé `yield` pour produire une séquence de valeurs. Elle génère les valeurs un par un au fur et à mesure, ce qui peut être plus efficace que la création d'une liste complète, surtout pour des séquences de données très grandes.
Comment utiliser un générateur?
Pour utiliser un générateur, vous appelez simplement la fonction qui le définit. Elle retourne un objet générateur qui peut être itéré sur en utilisant une boucle `for` ou en appelant sa méthode `__next__()` pour obtenir les valeurs un par un.
Quelles sont les avantages des générateurs?
Les générateurs offrent plusieurs avantages. Ils permettent de consommer moins de mémoire car ils génèrent les valeurs au fur et à mesure, ce qui est particulièrement utile pour traiter des données volumineuses. De plus, ils rendent le code plus clair et plus efficace en évitant la création de structures de données temporaires.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.