Nov 23, 2024

Wiki

Python

Aide

edit SideBar

Search

Les Generators


Présentation

Les generators, introduits dans la version 2.2, offrent une technique de programmation originale, qui permet à une fonction ou une méthode de renvoyer des résultats intermédiaires.

Le mot-clef return est remplacé par yield.

La première fois que ce mot est rencontré, l'exécution est stoppéen et un objet de type generator est renvoyé, qui contient le contexte local de la fonction, et une méthode next

A chaque appel de cette méthode, la fonction est appelée jusqu'au prochain yield.

Un premier exemple

On définit une fonction avec trois yield (et aucun return). On va voir que

  • au premier appel, c'est le premier yield qui sera retourné,
  • au deuxième appel, ce sera le second,
  • etc.

Définissons notre generator :

  >>> def ca_compte():
  ...     yield 'Et de un'
  ...     yield 'Et de deux'
  ...     yield 'Et de trois'
  ... 
  >>> je_compte = ca_compte()

Premier appel...

  >>> je_compte.next()
  'Et de un'

Et ça continue ainsi, de yield en yield...

  >>> je_compte.next()
  'Et de deux'
  >>> je_compte.next()
  'Et de trois'

Enfin, une fois que tous les yield ont été appelés, une exception StopIteration est levée...

  >>> jeCompte.next()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  StopIteration

Utilisation dans une boucle

La méthode next pour passer à la prochaine valeur, et la levée de l'exception StopIteration, rendent les generators compatibles avec les boucles :

  >>> je_compte = ca_compte()
  >>> for element in je_compte:
  ...     print element
  ...
  Et de un
  Et de deux
  Et de trois

Exemple complet d'utilisation

Suite de Fibonacci

Voici à quoi peuvent servir les generators, en l'occurence à programmer proprement la suite de Fibonacci :

  >>> def fibonacci():
  ...     a, b = 0, 1
  ...     while True:
  ...         yield b
  ...         a, b = b, a+b
  ...
  >>> suite = fibonacci()
  >>> n = input('Combien de termes ? ')
  >>> for k in range(n):
  ...     print suite.next(),
  ...
  1, 1, 2, 3, 5, 8, 13, 21, 34, 55

On a mis un yield dans une boucle while infinie : on pourra donc appeler autant de fois que l'on veut suite.next(). Cette manière de procéder peut se réutiliser dans plein de contextes différents.

Nombres premiers

Le generator suivant permet d'obtenir autant de nombres premiers que l'on veut :

  >>> def nombre_premier():
  ...     nombre = 2
  ...     premiers = [2]
  ...     yield nombre
  ...     while True:
  ...         nombre += 1
  ...         if len([k for k in premiers if nombre%k == 0]) == 0:
  ...             yield nombre
  ...             premiers.append(nombre)
  ... 
  >>> premier = nombre_premier()
  >>> premier.next()
  2
  >>> premier.next() 
  3
  >>> premier.next()
  5
  >>> premier.next()
  7
  >>> premier.next()
  11

Les genexp

Les generators expressions (genexp) fournit une écriture concise pour les generators simples, en se basant sur les list comprehensions : les crochets de ces dernières sont remplacées par des parenthèses...

  >>> gen = ( k for k in range(10) if k%3 == 0)
  >>> gen.next()
  0
  >>> gen.next()
  3
  >>> gen.next()
  6
  >>> gen.next()
  9
  >>> gen.next()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  StopIteration

Pour aller plus loin

Le module itertools offre des outils avancés pour travailler sur les generators.

Page Actions

Recent Changes

Group & Page

Back Links