Restablecer el objeto generador en Python

Resuelto Dewfy asked hace 15 años • 18 respuestas

Tengo un objeto generador devuelto por rendimiento múltiple. La preparación para llamar a este generador requiere bastante tiempo. Por eso quiero reutilizar el generador varias veces.

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

Por supuesto, estoy pensando en copiar el contenido en una lista simple. ¿Hay alguna manera de restablecer mi generador?


Ver también: ¿Cómo mirar hacia adelante un elemento (vistazo) en un generador de Python?

Dewfy avatar Aug 13 '09 18:08 Dewfy
Aceptado

Los generadores no se pueden rebobinar. Tienes las siguientes opciones:

  1. Ejecute nuevamente la función del generador, reiniciando la generación:

    y = FunctionWithYield()
    for x in y: print(x)
    y = FunctionWithYield()
    for x in y: print(x)
    
  2. Almacene los resultados del generador en una estructura de datos en la memoria o en el disco que pueda iterar nuevamente:

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

La desventaja de la opción 1 es que vuelve a calcular los valores. Si eso consume mucha CPU, terminarás calculando dos veces. Por otro lado, la desventaja del 2 es el almacenamiento. La lista completa de valores se almacenará en la memoria. Si hay demasiados valores, esto puede resultar poco práctico.

Así que tenemos el clásico equilibrio entre memoria y procesamiento . No puedo imaginar una forma de rebobinar el generador sin almacenar los valores o calcularlos nuevamente.

También podría usar teelo sugerido por otras respuestas; sin embargo, eso aún almacenaría la lista completa en la memoria en su caso, por lo que serían los mismos resultados y un rendimiento similar a la opción 2.

nosklo avatar Aug 13 '2009 11:08 nosklo

Otra opción es utilizar la itertools.tee()función para crear una segunda versión de tu generador:

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

Esto podría ser beneficioso desde el punto de vista del uso de la memoria si la iteración original no procesara todos los elementos.

Ants Aasma avatar Aug 13 '2009 11:08 Ants Aasma
>>> 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
aaab avatar Oct 16 '2013 12:10 aaab