iteradores generadores generadoras generador funciones español codigo python generator

generadores - python funciones generadoras



Obtener el artículo nth de un generador en Python (6)

¿Hay alguna forma sintácticamente más concisa de escribir lo siguiente?

gen = (i for i in xrange(10)) index = 5 for i, v in enumerate(gen): if i is index: return v

Parece casi natural que un generador tenga una expresión gen[index] , que actúe como una lista, pero que sea funcionalmente idéntica al código anterior.


Discutiría contra la tentación de tratar a los generadores como listas. El enfoque simple pero ingenuo es el simple de una sola línea:

gen = (i for i in range(10)) list(gen)[3]

Pero recuerda, los generadores no son como listas. No almacenan sus resultados intermedios en ningún lugar, por lo que no puede retroceder. Demostraré el problema con un ejemplo simple en la respuesta de python:

>>> gen = (i for i in range(10)) >>> list(gen)[3] 3 >>> list(gen)[3] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range

Una vez que comience a pasar por un generador para obtener el enésimo valor de la secuencia, ahora el generador se encuentra en un estado diferente, y al intentar obtener el enésimo valor nuevamente le devolverá un resultado diferente, lo que probablemente resulte en un error en su código.

Veamos otro ejemplo, basado en el código de la pregunta.

Uno esperaría inicialmente lo siguiente para imprimir 4 dos veces.

gen = (i for i in range(10)) index = 4 for i, v in enumerate(gen): if i == index: answer = v break print(answer) for i, v in enumerate(gen): if i == index: answer = v break print(answer)

pero escribe esto en la respuesta y obtendrás:

>>> gen = (i for i in range(10)) >>> index = 4 >>> for i, v in enumerate(gen): ... if i == index: ... answer = v ... break ... >>> print(answer) 4 >>> for i, v in enumerate(gen): ... if i == index: ... answer = v ... break ... >>> print(answer) 9

Buena suerte rastreando ese error.

EDITAR:

Como se señaló, si el generador es infinitamente largo, ni siquiera se puede convertir a una lista. La list(gen) expresiones list(gen) nunca terminará.

Hay una forma en que podría colocar un envoltorio de almacenamiento en caché evaluado perezosamente alrededor de un generador infinito para que se vea como una lista infinitamente larga que podría indexar a voluntad, pero eso merece su propia pregunta y respuesta, y tendría importantes implicaciones de rendimiento.


Lo primero que me vino a la mente fue:

gen = (i for i in xrange(10)) index = 5 for i, v in zip(range(index), gen): pass return v


Puedes hacer esto, usando la count como un generador de ejemplo:

from itertools import islice, count next(islice(count(), n, n+1))


Tal vez debería elaborar más sobre un caso de uso real.

>>> gen = xrange(10) >>> ind=5 >>> gen[ind] 5


Un método sería utilizar itertools.islice

>>> next(itertools.islice(xrange(10), 5, 5 + 1)) 5


simplemente puede convertir el generador en una lista y usar el índice normalmente:

>>> [i for i in range(10)][index] 5