Dessine-moi un générateur
Ils sont généralement créés par des fonctions construites à l'aide du mot clef yield. Par abus de langage ces fonctions sont parfois appelées générateurs.
Un exemple pour mieux comprendre cela :
>>> gen = function()
Tu pourrais illustrer l'abus de langage en ajoutant ces lignes :
Altérer un générateur avec send
Au moment où il arrive sur une instruction yield, le générateur se met en pause. Mais à l'itération suivante, l'exécution reprend au niveau de ce même yield.
Je chipote, mais je ne comprends pas trop le "mais".
Dans le cas où vous appelez send, l'exécution reprend, et yield renvoie une valeur, celle passée lors du send.
Le "renvoie une valeur" prête à confusion, puisque pour moi, yield 2
renvoie un valeur, alors que toi tu parles de x = yield
.
Pour obtenir le comportement attendu, nous pourrions avancer dans les itérations uniquement si le dernier yield a renvoyé None.
J'ai bloqué là-dessus. Tu pourrais expliciter avec un truc du genre : "si le dernier yield a renvoyé None, c'est-à-dire si on l'a atteint via un next
et non un send
".
Par une boucle qui exécute des yield tant que ceux-ci ne renvoient pas None.
Le programme qui suit n'est pas simple à comprendre. Comme il est judicieux de laisser le lecteur jouer avec pour se l'approprier, peut-être pourrais-tu simplifier cela en enlevant les caractères ajoutés par l'interpréteur pour qu'on puisse récupérer directement un code fonctionnel ?
Déléguer à un autre générateur avec yield from
À la différence près qu'avec yield from, les paramètres passés avec send sont aussi relégués aux sous-générateurs.
Un exemple ?
On peut aussi noter que yield from n'attend pas nécessairement un générateur, mais n'importe quel type d'itérable.
Plus une question qu'une remarque : pourquoi avoir illustré cela dans gen1
et ne pas avoir fait :
| def gen2():
yield 0
yield from [1, 2, 3]
yield 4
|
D'autre part, tu pourrais introduire yield from
à partir d'un exemple concret (comme tu l'as fait avec la file dans la section précédente) plutôt qu'avec des fonctions sans sens particulier.
Listes et générateurs en intension
Listes en intension
Pourquoi ne pas utiliser un titre de niveau 1 ? Est-ce un problème de conversion GH vers ZdS ?
un peu à la manière de map
map
?
>>> [i + 1 for line in matrix for i in line]
Je chipote, mais i
prête à confusion, vu qu'on l'utilise souvent pour désigner l'indice de ligne d'une matrice. Plutôt x
ou n
?
De la même manière que pour les listes, nous pouvons définir des générateurs en intension (generator expressions) :
Peut-être pourrais-tu ajouter un passage sur l'utilité de cela ? Jusqu'à maintenant, tu nous as uniquement donné des générateurs "complexes". Là, la question qu'on pourrait se poser, c'est : pourquoi faire un générateur en intension plutôt qu'une liste en intension ?
Ah ben en fait tu dédies une section entière à la question. Peut-être du coup mettre une note à ce niveau, disant que tu réponds plus bas à la question.
Liste ou générateur ?
Il est aussi possible de profiter des avantages de l'un et de l'autre en récupérant une liste en fin de chaîne, par exemple en remplaçant la dernière ligne par :
Veux-tu dire par là que la liste que tu donnes après ne sera pas construite tout de suite, seulement générée au fur et à mesure qu'on récupère ses éléments ? Un exemple d'utilisation ne serait pas de refus.
TP : Un petit creux ?
>>> f = frigo(recettes, ('oeufs', 12), ('farine', 300), ('eau', 100), ('beurre', 250))
Pourquoi avoir choisi une telle interface, et pas :
| >>> frigo(recettes, {'oeufs': 12, ...})
# Ou, même si j'ai ma petite idée sur la question :
>>> f = frigo(recettes, [('oeufs', 12), ('farine', 300), ('eau', 100), ('beurre', 250)])
|
Quand plus aucune recette n'est réalisable, le générateur s'arrête.
Tu pourrais l'ajouter ou le mettre en exercice, mais il serait intéressant de ne pas arrêter le générateur, seulement le mettre en pause, de sorte qu'on puisse toujours ajouter des ingrédients.
Ce chapitre est excellent, l'enchaînement des propos très fluide et tout à fait progressif.
PS : une information que tu pourrais ajouter en introduction du tutoriel, c'est la dépendance entre les sections. Par exemple, pas besoin de connaître les générateurs pour passer aux décorateurs.