Cómo dividir un objeto generador o iterador en Python

Me gustaría hacer un bucle sobre un “segmento” de un iterador. No estoy seguro de si esto es posible porque entiendo que no es posible cortar un iterador. Lo que me gustaría hacer es esto:

def f(): for i in range(100): yield(i) x = f() for i in x[95:]: print(i) 

Esto por supuesto falla con:

 --------------------------------------------------------------------------- TypeError Traceback (most recent call last)  in () 4 x = f() 5 ----> 6 for i in x[95:]: 7 print(i) TypeError: 'generator' object is not subscriptable 

¿Hay una forma pythonica de recorrer un “segmento” de un generador?

Básicamente, el generador que realmente me interesa lee un archivo muy grande y realiza algunas operaciones línea por línea. Me gustaría probar los segmentos del archivo para asegurarme de que las cosas funcionen como se espera, pero requiere mucho tiempo para que se ejecute en todo el archivo.

Editar:
Como he mencionado, necesito hacer esto en un archivo. Esperaba que hubiera una forma de especificar esto explícitamente con el generador, por ejemplo:

 import skbio f = 'seqs.fna' seqs = skbio.io.read(f, format='fasta') 

seqs es un objeto generador

 for seq in itertools.islice(seqs, 30516420, 30516432): #do a bunch of stuff here pass 

El código anterior hace lo que necesito, sin embargo, sigue siendo muy lento, ya que el generador aún recorre todas las líneas. Esperaba solo hacer un bucle sobre la porción especificada

En general, la respuesta es itertools.islice , pero debe tener en cuenta que islice no lo hace, y no puede, en realidad omitir valores. Simplemente agarra y tira los valores de start antes de que comience a yield valores de yield . Entonces, por lo general, es mejor evitar la islice si es posible cuando necesita omitir muchos valores y / o los valores que se omiten son costosos de adquirir / calcular. Si puede encontrar una manera de no generar los valores en primer lugar, hágalo. En su ejemplo (obviamente creado), simplemente ajustaría el índice de inicio para el objeto de range .

En los casos específicos de tratar de ejecutarse en un objeto de archivo, puede que no sea ideal tirar de una gran cantidad de líneas (especialmente la lectura desde un medio lento). Suponiendo que no necesita líneas específicas, un truco que puede usar para evitar la lectura de grandes bloques del archivo, mientras se prueba una cierta distancia en el archivo, es la seek de un desplazamiento adivinado, que se lee hasta el final de la línea. (para descartar la línea parcial que probablemente buscó a la mitad de), luego islice las líneas que desee a partir de ese punto. Por ejemplo:

 import itertools with open('myhugefile') as f: # Assuming roughly 80 characters per line, this seeks to somewhere roughly # around the 100,000th line without reading in the data preceding it f.seek(80 * 100000) next(f) # Throw away the partial line you probably landed in the middle of for line in itertools.islice(f, 100): # Process 100 lines # Do stuff with each line 

Para el caso específico de archivos, es posible que también desee ver mmap que se puede usar de manera similar (y es inusualmente útil si está procesando bloques de datos en lugar de líneas de texto, posiblemente saltando al azar a medida que avanza).

Actualización: a partir de su pregunta actualizada, deberá consultar los documentos de su API y / o el formato de datos para averiguar exactamente cómo saltarse adecuadamente. Parece que skbio ofrece algunas funciones para omitir el uso de seq_num , pero aún así se leerá si no se procesa la mayoría del archivo . Si los datos se escribieran con la misma longitud de secuencia, vería los documentos en Alignment ; los datos alineados pueden cargarse sin procesar en absoluto los datos anteriores, por ejemplo, mediante el uso de Alignment.subalignment para crear nuevas Alignment que omitan el rest de los datos por usted .

No puede dividir un objeto generador o iterador utilizando una operación de división normal. En su lugar, debe usar itertools.islice como @jonrsharpe ya mencionado en su comentario .

 import iterator for i in iterator.islice(x, 95) print(i) 

También tenga en cuenta que islice devuelve un iterador y consume datos en el iterador o generador. Por lo tanto, tendrá que convertir sus datos en una lista o crear un nuevo objeto generador si necesita regresar y hacer algo o usar el itertools.tee poco conocido para crear una copia de su generador.

 from iterator import tee first, second = tee(f()) 

Islice es el camino pythonico

 from itertools import islice g = (i for i in range(100)) for num in islice(g, 95, None): print num