web-dev-qa-db-fra.com

Comment fonctionnent deux déclarations de rendement consécutives en python?

Je tombe sur ce code de pymotw.com dans la section fusion et fractionnement.

from itertools import *


def make_iterables_to_chain():
    yield [1, 2, 3]
    yield ['a', 'b', 'c']


for i in chain.from_iterable(make_iterables_to_chain()):
    print(i, end=' ')
print()

Je ne peux pas comprendre comment make_iterables_to_chain () fonctionne. Il contient deux déclarations de rendement, comment ça marche? Je sais comment fonctionnent les générateurs mais là mais il n'y avait qu'un seul rendement déclaration.

Aidez-moi, s'il vous plaît!

11
unnobtainium

De la même manière, un seul yield fonctionne.

Vous pouvez avoir autant de yields que vous le souhaitez dans un générateur, lorsque __next__ est appelé dessus, il s'exécutera jusqu'à ce qu'il tombe sur le prochain rendement. Vous récupérez ensuite l'expression produite et le générateur s'arrête jusqu'à ce qu'il soit __next__ la méthode est à nouveau invoquée.

Exécutez quelques appels next sur le générateur pour voir ceci:

>>> g = make_iterables_to_chain()  # get generator
>>> next(g) # start generator, go to first yield, get result
[1, 2, 3]
>>> next(g) # resume generator, go to second yield, get result
['a', 'b', 'c']
>>> # next(g) raises Exception since no more yields are found 

Un générateur permet effectivement à une fonction de retourner plusieurs fois. Chaque fois qu'une instruction yield est exécutée, la valeur est renvoyée à l'appelant et l'appelant peut continuer l'exécution de la fonction.

Habituellement, ils sont utilisés comme itérables dans les boucles for.

La fonction suivante incrémente chaque élément d'un itérable d'un montant:

def inc_each(nums, inc):
    for i in nums:
        yield i + inc

Voici un exemple d'utilisation:

gen = inc_each([1, 2, 3, 4], 100)
print(list(gen)) # [101, 102, 103, 104]

list est utilisé ici pour convertir un itérable arbitraire (dans ce cas un générateur) en une liste.

La fonction que vous décrivez exécute deux instructions de rendement:

def make_iterables_to_chain():
    yield [1, 2, 3]
    yield ['a', 'b', 'c']

Si vous l'appelez, il retourne un générateur qui, s'il est itéré, donne les listes [1, 2, 3] et ['a', 'b', 'c'].

gen = make_iterables_to_chain()
print(list(gen)) # [[1, 2, 3], ['a', 'b', 'c']]

itertools.chain.from_iterable prendra un (éventuellement infini) itérable d'itérables et "l'aplatira", retournant un (possible infini) itérable comme résultat.

Voici un moyen de le mettre en œuvre:

def from_iterable(iterables):
    for iterable in iterables:
        for i in iterable:
            yield i
0
Challenger5