Itérateur et Générateur

PythonPythonBeginner
Pratiquer maintenant

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce laboratoire, nous allons apprendre les Itérateurs, les Générateurs et les Expressions Génératrices intégrés à Python. Nous verrons comment ces constructions peuvent être utilisées pour écrire du code efficace et élégant en Python.

Objectifs

  • Itérateur
  • Générateur
  • Expression Génératrice

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ObjectOrientedProgrammingGroup(["Object-Oriented Programming"]) python(("Python")) -.-> python/ErrorandExceptionHandlingGroup(["Error and Exception Handling"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/ControlFlowGroup -.-> python/for_loops("For Loops") python/ControlFlowGroup -.-> python/list_comprehensions("List Comprehensions") python/FunctionsGroup -.-> python/function_definition("Function Definition") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("Classes and Objects") python/ErrorandExceptionHandlingGroup -.-> python/raising_exceptions("Raising Exceptions") python/AdvancedTopicsGroup -.-> python/iterators("Iterators") python/AdvancedTopicsGroup -.-> python/generators("Generators") subgraph Lab Skills python/for_loops -.-> lab-84{{"Itérateur et Générateur"}} python/list_comprehensions -.-> lab-84{{"Itérateur et Générateur"}} python/function_definition -.-> lab-84{{"Itérateur et Générateur"}} python/classes_objects -.-> lab-84{{"Itérateur et Générateur"}} python/raising_exceptions -.-> lab-84{{"Itérateur et Générateur"}} python/iterators -.-> lab-84{{"Itérateur et Générateur"}} python/generators -.-> lab-84{{"Itérateur et Générateur"}} end

Itérateur

Un itérateur est un objet sur lequel on peut itérer (faire une boucle). Un objet qui renverra des données, un élément à la fois. En Python, un itérateur est créé à partir d'un objet itérable, tel qu'une liste, un tuple ou une chaîne de caractères.

Ouvrez un nouvel interpréteur Python.

python3

Pour créer un itérateur en Python, nous devons implémenter deux méthodes dans notre objet : __iter__ et __next__.

__iter__ renvoie l'objet itérateur lui-même. La méthode __next__ renvoie la valeur suivante de l'itérateur. S'il n'y a plus d'éléments à renvoyer, elle doit lever StopIteration.

Voici un exemple d'un itérateur simple qui itère sur une liste de nombres :

class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        ## len() est le nombre d'éléments dans la liste
        if self.index >= len(self.data):
            raise StopIteration
        result = self.data[self.index]
        self.index += 1
        return result

iterator = MyIterator([1, 2, 3, 4, 5])
for x in iterator:
    print(x)

Sortie :

1
2
3
4
5

Les itérateurs sont utiles car ils nous permettent d'accéder aux éléments d'un itérable un à la fois, au lieu de charger tous les éléments en mémoire d'un coup. Cela peut être particulièrement utile lorsqu'on travaille avec de grands ensembles de données qui ne peuvent pas tenir en mémoire.

Les itérateurs sont également utilisés pour implémenter l'évaluation paresseuse en Python. Cela signifie que les éléments d'un itérateur ne sont générés que lorsqu'ils sont nécessaires, au lieu de générer tous les éléments d'entrée. C'est une approche peut être plus efficace, car elle nous permet d'éviter de générer et de stocker des éléments inutiles.

Si vous voulez obtenir un élément à la fois à partir d'un itérateur, vous pouvez utiliser la fonction next(). Cette fonction renverra l'élément suivant de l'itérateur. S'il n'y a plus d'éléments, elle levera une exception StopIteration.

iterator = MyIterator([1, 2, 3, 4, 5])
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))

## StopIteration
print(next(iterator))

Sortie :

1
2
3
4

## StopIteration

Voici quelques cas d'utilisation courants des itérateurs en Python :

  1. Parcourir les éléments d'un grand ensemble de données, un élément à la fois.
  2. Implémenter l'évaluation paresseuse d'un grand ensemble de données.
  3. Implémenter une logique d'itération personnalisée dans une classe.
  4. Les itérateurs sont un outil puissant en Python et peuvent être utilisés pour écrire du code efficace et élégant.

Générateur

Un générateur est un type spécial d'itérateur qui est créé à l'aide d'une fonction. C'est un moyen simple de créer un itérateur à l'aide d'une fonction.

Une fonction génératrice est définie comme une fonction normale, mais au lieu d'utiliser le mot clé return pour renvoyer une valeur, elle utilise le mot clé yield. Lorsque la fonction génératrice est appelée, elle n'exécute pas immédiatement le corps de la fonction. Au lieu de cela, elle renvoie un objet générateur qui peut être utilisé pour exécuter le corps de la fonction sur demande.

La fonction génératrice peut avoir une instruction yield à n'importe quel endroit de son corps. Lorsque la fonction génératrice est appelée, elle n'exécute pas immédiatement le corps de la fonction. Au lieu de cela, elle renvoie un objet générateur qui peut être utilisé pour exécuter le corps de la fonction sur demande.

Voici un exemple d'une fonction génératrice qui génère les carrés d'une liste de nombres :

def my_generator(data):
    for x in data:
        yield x**2

for x in my_generator([1, 2, 3, 4, 5]):
    print(x)

Sortie :

1
4
9
16
25

Les générateurs sont utiles car ils nous permettent de générer des éléments sur demande, au lieu de générer tous les éléments d'entrée. C'est une approche peut être plus efficace, car elle nous permet d'éviter de générer et de stocker des éléments inutiles.

Les générateurs sont également utilisés pour implémenter l'évaluation paresseuse en Python. Cela signifie que les éléments d'un générateur ne sont générés que lorsqu'ils sont nécessaires, au lieu de générer tous les éléments d'entrée. C'est une approche peut être plus efficace, car elle nous permet d'éviter de générer et de stocker des éléments inutiles.

Voici quelques cas d'utilisation courants des générateurs en Python :

  1. Générer des éléments sur demande, au lieu de générer tous les éléments d'entrée.
  2. Implémenter l'évaluation paresseuse d'un grand ensemble de données.
  3. Implémenter une logique d'itération personnalisée dans une fonction.
  4. Les générateurs sont un outil puissant en Python et peuvent être utilisés pour écrire du code efficace et élégant.

Différences entre Itérateur et Générateur

La principale différence entre un itérateur et un générateur est la manière dont ils sont implémentés.

Un itérateur est un objet qui implémente deux méthodes : __iter__ et __next__. La méthode __iter__ renvoie l'objet itérateur lui-même, et la méthode __next__ renvoie la valeur suivante de l'itérateur.

Un générateur est une fonction qui utilise le mot clé yield pour renvoyer une valeur. Lorsque la fonction génératrice est appelée, elle n'exécute pas immédiatement le corps de la fonction. Au lieu de cela, elle renvoie un objet générateur qui peut être utilisé pour exécuter le corps de la fonction sur demande.

Voici un résumé des principales différences entre itérateurs et générateurs :

  1. Les itérateurs sont des objets qui implémentent les méthodes __iter__ et __next__. Ils sont créés à partir d'objets itérables, tels que des listes, des tuples ou des chaînes de caractères.
  2. Les générateurs sont des fonctions qui utilisent le mot clé yield pour renvoyer une valeur. Ils sont créés en appelant une fonction génératrice.
  3. Les itérateurs peuvent être implémentés à l'aide d'une classe, tandis que les générateurs sont implémentés à l'aide d'une fonction.
  4. Les itérateurs renvoient un élément à la fois, tandis que les générateurs renvoient un objet générateur qui peut être utilisé pour générer des éléments sur demande.
  5. Les itérateurs sont utilisés pour accéder aux éléments d'un objet itérable un à la fois, tandis que les générateurs sont utilisés pour générer des éléments sur demande.

Dans l'ensemble, à la fois les itérateurs et les générateurs sont des outils utiles pour itérer sur une séquence d'éléments en Python. Ils nous permettent d'accéder ou de générer les éléments d'une séquence un à la fois, ce qui peut être plus efficace que de générer tous les éléments d'entrée.

Exemple avancé : Générateur de nombres premiers

Dans cet exemple, nous allons créer un générateur qui génère des nombres premiers.

Tout d'abord, définissons une fonction d'aide _is_prime qui renvoie True si un nombre est premier et False sinon :

def _is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

Maintenant, définissons notre fonction génératrice prime_numbers :

def prime_numbers(n):
    for i in range(2, n+1):
        if _is_prime(i):
            yield i

Testons notre générateur :

for prime in prime_numbers(20):
    print(prime)

Sortie :

2
3
5
7
11
13
17
19

Expression génératrice

Une expression génératrice est similaire à une compréhension de liste, mais au lieu de créer une liste, elle renvoie un objet générateur.

Une expression génératrice est définie en utilisant des parenthèses (), et peut inclure une ou plusieurs clauses for. Elle est évaluée sur demande et renvoie un objet générateur qui peut être utilisé pour générer les éléments de l'expression sur demande.

Voici un exemple d'expression génératrice qui génère les carrés d'une liste de nombres :

generator = (x**2 for x in [1, 2, 3, 4, 5])
for x in generator:
    print(x)

Sortie :

1
4
9
16
25

Les expressions génératrices sont utiles car elles nous permettent de générer des éléments sur demande, au lieu de générer tous les éléments d'entrée. C'est une approche peut être plus efficace, car elle nous permet d'éviter de générer et de stocker des éléments inutiles.

Les expressions génératrices sont également utilisées pour implémenter l'évaluation paresseuse en Python. Cela signifie que les éléments d'une expression génératrice ne sont générés que lorsqu'ils sont nécessaires, au lieu de générer tous les éléments d'entrée. C'est une approche peut être plus efficace, car elle nous permet d'éviter de générer et de stocker des éléments inutiles.

Voici quelques cas d'utilisation courants des expressions génératrices en Python :

  1. Générer des éléments sur demande, au lieu de générer tous les éléments d'entrée.
  2. Implémenter l'évaluation paresseuse d'un grand ensemble de données.
  3. Écrire du code concis et efficace.

Les expressions génératrices sont un outil puissant en Python et peuvent être utilisées pour écrire du code efficace et élégant.

Expression génératrice et compréhension de liste

Voici un exemple d'une compréhension de liste et d'une expression génératrice qui génèrent les carrés d'une liste de nombres :

## Compréhension de liste
squares = [x**2 for x in [1, 2, 3, 4, 5]]
print(squares)

## Expression génératrice
squares_generator = (x**2 for x in [1, 2, 3, 4, 5])
for x in squares_generator:
    print(x)

Sortie :

[1, 4, 9, 16, 25]
1
4
9
16
25

Il existe plusieurs similitudes et différences entre les comprehensions de liste et les expressions génératrices :

Similitudes

  1. Les deux, les comprehensions de liste et les expressions génératrices, sont utilisées pour générer une séquence d'éléments.
  2. Les deux utilisent la même syntaxe, avec une ou plusieurs clauses for et une expression pour générer les éléments.

Différences

  1. Une compréhension de liste génère une liste, tandis qu'une expression génératrice génère un objet générateur.
  2. Une compréhension de liste génère tous les éléments de la liste d'entrée, tandis qu'une expression génératrice génère les éléments sur demande.
  3. Une compréhension de liste utilise plus de mémoire, car elle stocke tous les éléments dans une liste, tandis qu'une expression génératrice utilise moins de mémoire, car elle génère les éléments sur demande.
  4. Une compréhension de liste est généralement plus rapide à exécuter, car elle génère tous les éléments d'entrée, tandis qu'une expression génératrice est généralement plus lente, car elle génère les éléments sur demande.

Dans l'ensemble, les deux, les comprehensions de liste et les expressions génératrices, sont des outils utiles pour générer une séquence d'éléments en Python. Les comprehensions de liste sont généralement plus rapides et utilisent plus de mémoire, tandis que les expressions génératrices sont généralement plus lentes et utilisent moins de mémoire. Lequel utiliser dépend des exigences spécifiques de l'application.

Sommaire

Dans ce laboratoire, nous avons appris sur les itérateurs, les générateurs et les expressions génératrices intégrés à Python. Nous avons vu comment ces constructions peuvent être utilisées pour écrire du code efficace et élégant en Python. Nous avons également vu un exemple de l'utilisation des générateurs pour implémenter un générateur de nombres premiers.