Tengo una función de generador como la siguiente:
def myfunct():
...
yield result
La forma habitual de llamar a esta función sería:
for r in myfunct():
dostuff(r)
Mi pregunta, ¿hay alguna manera de obtener solo un elemento del generador cuando lo desee? Por ejemplo, me gustaría hacer algo como:
while True:
...
if something:
my_element = pick_just_one_element(myfunct())
dostuff(my_element)
...
python
iterator
generator
python-2.x
Alexandros
fuente
fuente
next(gen, default)
También se puede utilizar para evitar laStopIteration
excepción. Por ejemplo,next(g, None)
para un generador de cadenas producirá una cadena o Ninguna después de que finalice la iteración.next(g)
. Esto llamará internamenteg.__next__()
, pero realmente no tiene que preocuparse por eso, así como generalmente no le importa quelen(a)
las llamadas internasa.__len__()
.g.next()
estág.__next__()
en py3k. El builtinnext(iterator)
ha existido desde Python 2.6, y es lo que se debe usar en todos los nuevos códigos de Python, y es trivial para la implementación posterior si necesita admitir py <= 2.5.Para elegir solo un elemento de un generador, use
break
en unafor
declaración, olist(itertools.islice(gen, 1))
Según su ejemplo (literalmente) puede hacer algo como:
Si desea " obtener solo un elemento del generador [una vez generado] cuando quiera " (supongo que el 50% es la intención original y la intención más común) entonces:
De esta manera,
generator.next()
se puede evitar el uso explícito de , y el manejo de fin de entrada no requiere (críptico)StopIteration
manejo de excepciones o comparaciones de valores predeterminados adicionales.La sección
else:
defor
declaración solo es necesaria si desea hacer algo especial en caso de fin de generador.Nota sobre
next()
/.next()
:En Python3
.next()
se cambió el nombre del método.__next__()
por una buena razón: se considera de bajo nivel (PEP 3114). Antes de Python 2.6, la función integradanext()
no existía. E incluso se discutió la posibilidad de pasarnext()
aloperator
módulo (lo que habría sido prudente), debido a su rara necesidad y la cuestionable inflación de los nombres incorporados.Usar
next()
sin valor predeterminado sigue siendo una práctica de muy bajo nivel: lanzar el crípticoStopIteration
como un rayo de la nada en el código de aplicación normal abiertamente. Y usarnext()
con centinela predeterminado, que mejor debería ser la única opción para unnext()
directamente enbuiltins
, es limitado y a menudo da razón a una lógica / legibilidad no pitónica extraña.En pocas palabras: Usar next () debería ser muy raro, como usar funciones del
operator
módulo. El uso defor x in iterator
,islice
,list(iterator)
y otras funciones de aceptar un iterador sin problemas es la forma natural de usar iteradores de nivel de aplicación - y bastante siempre es posible.next()
es de bajo nivel, un concepto adicional, no obvio, como lo muestra la pregunta de este hilo. Mientras que, por ejemplo, el usobreak
enfor
es convencional.fuente
mySeq.head
?No creo que haya una manera conveniente de recuperar un valor arbitrario de un generador. El generador proporcionará un método next () para atravesarse, pero la secuencia completa no se produce inmediatamente para ahorrar memoria. Esa es la diferencia funcional entre un generador y una lista.
fuente
Para aquellos de ustedes que escanean estas respuestas para obtener un ejemplo de trabajo completo para Python3 ... bueno, aquí van:
Esto produce:
fuente
El generador es una función que produce un iterador. Por lo tanto, una vez que tenga una instancia de iterador, use next () para obtener el siguiente elemento del iterador. Como ejemplo, use la función next () para obtener el primer elemento, y luego use
for in
para procesar los elementos restantes:fuente
asegúrese de atrapar la excepción lanzada después de tomar el último elemento
fuente
Creo que la única forma es obtener una lista del iterador y luego obtener el elemento que desea de esa lista.
fuente
myfunct()
genera una gran cantidad de valores) ya que puede usar la función integradanext
para obtener el siguiente valor generado.