seqio - read fasta python
Cómo len(generador()) (8)
Esta pregunta ya tiene una respuesta aquí:
- Longitud de salida del generador [duplicado] 9 respuestas
Los generadores Python son muy útiles. Tienen ventajas sobre las funciones que devuelven listas. Sin embargo, puede len(list_returning_function())
. ¿Hay alguna forma de len(generator_function())
?
ACTUALIZAR:
Por supuesto len(list(generator_function()))
funcionaría .....
Intento usar un generador que he creado dentro de un nuevo generador que estoy creando. Como parte del cálculo en el nuevo generador, necesita conocer la longitud del antiguo. Sin embargo, me gustaría mantenerlos a ambos con las mismas propiedades que un generador, específicamente, no mantener toda la lista en la memoria, ya que puede ser muy larga.
ACTUALIZACIÓN 2:
Supongamos que el generador sabe que es la longitud del objetivo, incluso desde el primer paso. Además, no hay razón para mantener la sintaxis len()
. Ejemplo: si las funciones en Python son objetos, ¿no podría asignar la longitud a una variable de este objeto que sería accesible para el nuevo generador?
La conversión a la list
que se ha sugerido en las otras respuestas es la mejor manera si aún desea procesar los elementos del generador después, pero tiene un defecto: usa memoria O (n). Puede contar los elementos en un generador sin usar tanta memoria con:
sum(1 for x in generator)
Por supuesto, tenga en cuenta que esto podría ser más lento que len(list(generator))
en las implementaciones comunes de Python, y si los generadores son lo suficientemente largos como para que la complejidad de la memoria importe, la operación llevaría bastante tiempo. Aún así, personalmente prefiero esta solución ya que describe lo que quiero obtener, y no me da nada adicional que no sea necesario (como una lista de todos los elementos).
También escuche los consejos de delnan: si está descartando la salida del generador, es muy probable que haya una manera de calcular la cantidad de elementos sin ejecutarlo, o contándolos de otra manera.
Los generadores no tienen longitud, después de todo no son colecciones.
Los generadores son funciones con un estado interno (y una sintaxis refinada). Puede llamarlos repetidamente para obtener una secuencia de valores, de modo que pueda usarlos en bucle. Pero no contienen ningún elemento, por lo que pedir la longitud de un generador es como pedir la duración de una función.
si las funciones en Python son objetos, ¿no podría asignar la longitud a una variable de este objeto que sería accesible para el nuevo generador?
Las funciones son objetos, pero no puede asignarles nuevos atributos. La razón es probablemente para mantener un objeto tan básico tan eficiente como sea posible.
Sin embargo, puede simplemente devolver pares (generator, length)
de sus funciones o ajustar el generador en un objeto simple como este:
class GeneratorLen(object):
def __init__(self, gen, length):
self.gen = gen
self.length = length
def __len__(self):
return self.length
def __iter__(self):
return self.gen
g = some_generator()
h = GeneratorLen(g, 1)
print len(h), list(h)
Puede combinar los beneficios de los generadores con la certeza de len()
, al crear su propio objeto iterable:
class MyIterable(object):
def __init__(self, n):
self.n = n
def __len__(self):
return self.n
def __iter__(self):
self._gen = self._generator()
return self
def _generator(self):
# Put your generator code here
i = 0
while i < self.n:
yield i
i += 1
def next(self):
return next(self._gen)
mi = MyIterable(100)
print len(mi)
for i in mi:
print i,
Esto es básicamente una implementación simple de xrange
, que devuelve un objeto que puede tomarse en cuenta, pero no crea una lista explícita.
Puede usar len(list(generator_function())
. Sin embargo, esto consume el generador, pero esa es la única forma en que puede averiguar cuántos elementos se generan. Por lo tanto, es posible que desee guardar la lista en alguna parte si también desea utilizar el generador. artículos.
a = list(generator_function())
print(len(a))
print(a[0])
Puede usar send
como un hack:
def counter():
length = 10
i = 0
while i < length:
val = (yield i)
if val == ''length'':
yield length
i += 1
it = counter()
print(it.next())
#0
print(it.next())
#1
print(it.send(''length''))
#10
print(it.next())
#2
print(it.next())
#3
Puedes len(list(generator))
pero probablemente puedas hacer algo más eficiente si realmente quieres descartar los resultados.
Puedes usar reduce
.
Para Python 3:
>>> import functools
>>> def gen():
... yield 1
... yield 2
... yield 3
...
>>> functools.reduce(lambda x,y: x + 1, gen(), 0)
En Python 2, reduce
está en el espacio de nombres global por lo que la importación es innecesaria.
Supongamos que tenemos un generador:
def gen():
for i in range(10):
yield i
Podemos envolver el generador, junto con la longitud conocida, en un objeto:
import itertools
class LenGen(object):
def __init__(self,gen,length):
self.gen=gen
self.length=length
def __call__(self):
return itertools.islice(self.gen(),self.length)
def __len__(self):
return self.length
lgen=LenGen(gen,10)
Las instancias de LenGen
son generadores en sí mismas, ya que llamarlas devuelve un iterador.
Ahora podemos usar el generador de lgen
en lugar de gen
, y acceder a len(lgen)
también:
def new_gen():
for i in lgen():
yield float(i)/len(lgen)
for i in new_gen():
print(i)