181 votes

Réinitialisation du générateur de l'objet en Python

J'ai générateur de l'objet renvoyé par multiples de rendement. Préparation à l'appel de ce générateur est plutôt temps de l'opération. C'est pourquoi je veux réutiliser générateur à plusieurs reprises.

y = FunctionWithYield()
for x in y: print(x)
#here must be something to reset 'y'
for x in y: print(x)

Bien sûr, je suis prise dans l'esprit de la copie de contenu dans la liste simple.

170voto

nosklo Points 75862

Les générateurs peuvent pas être réutilisé. Vous disposez des options suivantes:

  1. Exécuter la fonction de générateur de nouveau, le redémarrage de la production:

    y = FunctionWithYield()
    for x in y: print(x)
    y = FunctionWithYield()
    for x in y: print(x)
    
  2. Stocker le générateur de résultats dans une structure de données sur la mémoire ou le disque que vous pouvez parcourir à nouveau:

    y = list(FunctionWithYield())
    for x in y: print(x)
    # can iterate again:
    for x in y: print(x)
    

L'inconvénient de l'option 1 , c'est qu'il calcule les valeurs de nouveau. Si c'est CPU-intensive, en fin de calcul deux fois. D'autre part, l'inconvénient de l' 2 est le stockage. L'ensemble de la liste de valeurs seront stockées sur la mémoire. Si il y a trop de valeurs, qui peut être peu pratique.

Si vous avez le classique entre mémoire et de traitement de compromis. Je ne peux pas imaginer un moyen de rembobinage du générateur sans stocker les valeurs ou les calculer de nouveau.

142voto

Ants Aasma Points 22921

Une autre option est d'utiliser l' itertools.tee() fonction pour créer une deuxième version de votre générateur:

y = FunctionWithYield()
y, y_backup = tee(y)
for x in y:
    print(x)
for x in y_backup:
    print(x)

Cela pourrait être bénéfique de l'utilisation de la mémoire de point de vue si la première itération peut pas traiter tous les éléments.

41voto

aaab Points 41
>>> def gen():
...     def init():
...         return 0
...     i = init()
...     while True:
...         val = (yield i)
...         if val=='restart':
...             i = init()
...         else:
...             i += 1

>>> g = gen()
>>> g.next()
0
>>> g.next()
1
>>> g.next()
2
>>> g.next()
3
>>> g.send('restart')
0
>>> g.next()
1
>>> g.next()
2

31voto

Aaron Digulla Points 143830

Probablement la solution la plus simple consiste à envelopper la partie coûteuse dans un objet et le passer à la génératrice:

data = ExpensiveSetup()
for x in FunctionWithYield(data): pass
for x in FunctionWithYield(data): pass

De cette façon, vous pouvez mettre en cache le coûteux calculs.

Si vous pouvez garder tous les résultats dans la mémoire RAM en même temps, puis utilisez list() de matérialiser les résultats de la génératrice dans une simple liste et de travailler avec cela.

5voto

Hank Gay Points 36173

Si GrzegorzOledzki réponse ne suffira pas, vous pourriez probablement utiliser send() pour atteindre votre objectif. Voir PEP-0342 pour plus de détails sur le renforcement de générateurs et de rendement des expressions.

Mise à JOUR: voir Aussi itertools.tee(). Elle implique la mémoire vs traitement compromis mentionné ci-dessus, mais il peut économiser de la mémoire sur l'enregistrement du générateur de résultats en list; il dépend de la façon dont vous utilisez le générateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X