with - what are python generators used for
¿Cómo puedo saber si un generador recién se inició? (3)
Esto solo funciona en Python 3.2+:
>>> def gen(): yield 0; yield 1
...
>>> a = gen()
>>> import inspect
>>> inspect.getgeneratorstate(a)
''GEN_CREATED''
>>> next(a)
0
>>> inspect.getgeneratorstate(a)
''GEN_SUSPENDED''
>>> next(a)
1
>>> inspect.getgeneratorstate(a)
''GEN_SUSPENDED''
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> inspect.getgeneratorstate(a)
''GEN_CLOSED''
Entonces, la función solicitada es:
import inspect
def is_just_started(gen):
return inspect.getgeneratorstate(gen) == inspect.GEN_CREATED:
Por curiosidad, busqué en CPython para descubrir cómo estaba determinando esto ... Aparentemente se ve en generator.gi_frame.f_lasti
que es el "índice del último intento de instrucción en bytecode". Si es -1
entonces aún no ha comenzado.
Aquí hay una versión de py2:
def is_just_started(gen):
return gen.gi_frame is not None and gen.gi_frame.f_lasti == -1
Me gustaría una función, is_just_started
, que se comporte como la siguiente:
>>> def gen(): yield 0; yield 1
>>> a = gen()
>>> is_just_started(a)
True
>>> next(a)
0
>>> is_just_started(a)
False
>>> next(a)
1
>>> is_just_started(a)
False
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> is_just_started(a)
False
¿Cómo puedo implementar esta función?
Miré el atributo .gi_running
pero parece ser usado para otra cosa.
Si conozco el primer valor que debe enviarse al generador, puedo hacer algo como esto:
def safe_send(gen, a):
try:
return gen.send(a)
except TypeError as e:
if "just-started" in e.args[0]:
gen.send(None)
return gen.send(a)
else:
raise
Sin embargo, esto parece aborrecible.
Haga un nuevo generador que simplemente rinda de su generador de interés. Establece un indicador una vez que se ha consumido el primer valor . Después, simplemente puede usar el yield from
resto de los artículos.
Utilice el generador sustituto como sustituto del generador que le interesa para supervisar el estado "is_just_started".
Esta técnica no es intrusiva y se puede usar incluso en generadores para los cuales no tiene control sobre el código fuente.
Puede crear un iterador y establecer el indicador como la propiedad de la instancia en la clase de iterador como:
class gen(object):
def __init__(self, n):
self.n = n
self.num, self.nums = 0, []
self.is_just_started = True # Your flag
def __iter__(self):
return self
# Python 3 compatibility
def __next__(self):
return self.next()
def next(self):
self.is_just_started = False # Reset flag with next
if self.num < self.n:
cur, self.num = self.num, self.num+1
return cur
else:
raise StopIteration()
Y su función de verificación de valor sería como:
def is_just_started(my_generator):
return my_generator.is_just_started
Muestra de ejecución:
>>> a = gen(2)
>>> is_just_started(a)
True
>>> next(a)
0
>>> is_just_started(a)
False
>>> next(a)
1
>>> is_just_started(a)
False
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 19, in next
StopIteration
Para saber la diferencia entre el iterador y el generador , verifique la diferencia entre los generadores de Python y los iteradores