Corríjame si me equivoco, pero si pudiera hacer una solución realmente genérica para cualquier generador, sería el equivalente a establecer puntos de interrupción en las declaraciones de rendimiento y tener la capacidad de "retroceder". ¿Eso significaría clonar el marco de la pila en rendimientos y restaurarlos en StopIteration?
Bueno, supongo que restaurarlos StopIteration o no, pero al menos StopIteration te diría que estaba vacío. Si Necesito sueño ...
44
Creo que sé por qué quiere esto. Si está haciendo desarrollo web con plantillas y está pasando el valor de retorno a una plantilla como Cheetah o algo así, la lista vacía []es convenientemente Falsey para que pueda hacer un chequeo y hacer un comportamiento especial para algo o nada. Los generadores son verdaderos incluso si no producen elementos.
jpsimons
Aquí está mi caso de uso ... Estoy usando glob.iglob("filepattern")un patrón comodín proporcionado por el usuario, y quiero advertir al usuario si el patrón no coincide con ningún archivo. Claro que puedo solucionar esto de varias maneras, pero es útil poder probar limpiamente si el iterador se quedó vacío o no.
La respuesta simple a su pregunta: no, no hay una manera simple. Hay muchas soluciones alternativas.
Realmente no debería haber una manera simple, debido a lo que son los generadores: una forma de generar una secuencia de valores sin mantener la secuencia en la memoria . Por lo tanto, no hay recorrido hacia atrás.
Si lo desea, puede escribir una función has_next o incluso aplicarla a un generador como método con un elegante decorador.
bastante justo, eso tiene sentido. Sabía que no había forma de encontrar la longitud de un generador, pero pensé que podría haber perdido una forma de encontrarlo si inicialmente iba a generar algo.
Dan
1
Ah, y como referencia, intenté implementar mi propia sugerencia de "decorador elegante". DIFÍCIL. Aparentemente copy.deepcopy no funciona en generadores.
David Berger
47
No estoy seguro de poder estar de acuerdo con "no debería haber una manera simple". Hay muchas abstracciones en informática que están diseñadas para generar una secuencia de valores sin mantener la secuencia en la memoria, pero que le permiten al programador preguntar si hay otro valor sin eliminarlo de la "cola" si lo hay. Existe la posibilidad de mirar hacia adelante sin necesidad de "atravesar hacia atrás". Eso no quiere decir que un diseño de iterador deba proporcionar dicha característica, pero seguro que es útil. ¿Tal vez estás objetando porque el primer valor puede cambiar después del vistazo?
LarsH
9
Estoy objetando porque una implementación típica ni siquiera calcula un valor hasta que se necesita. Se podría forzar a la interfaz a hacer esto, pero eso podría ser subóptimo para implementaciones livianas.
David Berger
66
@ S.Lott no necesita generar la secuencia completa para saber si la secuencia está vacía o no. El valor de almacenamiento de un elemento es suficiente; vea mi respuesta.
Mark Ransom
98
Sugerencia:
def peek(iterable):try:
first = next(iterable)exceptStopIteration:returnNonereturn first, itertools.chain([first], iterable)
Uso:
res = peek(mysequence)if res isNone:# sequence is empty. Do stuff.else:
first, mysequence = res
# Do something with first, maybe?# Then iterate over the sequence:for element in mysequence:# etc.
No entiendo el punto de devolver el primer elemento dos veces return first, itertools.chain([first], rest).
njzk2
66
@ njzk2 Iba para una operación de "vistazo" (de ahí el nombre de la función). wiki "peek es una operación que devuelve el valor de la parte superior de la colección sin eliminar el valor de los datos"
John Fouhy
Esto no funcionará si el generador está diseñado para no producir ninguno. def gen(): for pony in range(4): yield None if pony == 2 else pony
Paul
44
@Paul Mira los valores de retorno de cerca. Si el generador está listo, es decir, no regresa None, sino que sube StopIteration, el resultado de la función es None. De lo contrario, es una tupla, que no lo es None.
Financia la demanda de Mónica el
Esto me ayudó mucho con mi proyecto actual. Encontré un ejemplo similar en el código para el módulo de biblioteca estándar de python 'buzón.py'. This method is for backward compatibility only. def next(self): """Return the next message in a one-time iteration.""" if not hasattr(self, '_onetime_keys'): self._onetime_keys = self.iterkeys() while True: try: return self[next(self._onetime_keys)] except StopIteration: return None except KeyError: continue
igual
29
Una manera simple es usar el parámetro opcional para next () que se usa si el generador está agotado (o vacío). Por ejemplo:
No. Esto es incorrecto para cualquier generador en el que el primer valor obtenido sea falso.
mehtunguh
77
Use un en object()lugar de classpara hacerlo una línea más corta _exhausted = object():; if next(iterable, _exhausted) is _exhausted:
Messa
13
next(generator, None) is not None
O reemplazar None, pero cualquier valor que sabe que es no en el generador.
Editar : Sí, esto saltará 1 elemento en el generador. A menudo, sin embargo, verifico si un generador está vacío solo para fines de validación, luego realmente no lo uso. O de lo contrario hago algo como:
def foo(self):if next(self.my_generator(),None)isNone:raiseException("Not initiated")for x in self.my_generator():...
Es decir, esto funciona si su generador proviene de una función , como en generator().
¿Por qué esta no es la mejor respuesta? En caso de que el generador regrese None?
Sait
8
Probablemente porque esto te obliga a consumir el generador en lugar de solo probar si está vacío.
bfontaine
3
Es malo porque en el momento en que llama al siguiente (generador, Ninguno) omitirá 1 elemento si está disponible
Nathan Do
Correcto, vas a perder el primer elemento de tu gen y también vas a consumir tu gen en lugar de probar si está vacío.
AJ
12
El mejor enfoque, en mi humilde opinión, sería evitar una prueba especial. La mayoría de las veces, el uso de un generador es la prueba:
thing_generated =False# Nothing is lost here. if nothing is generated, # the for block is not executed. Often, that's the only check# you need to do. This can be done in the course of doing# the work you wanted to do anyway on the generated output.for thing in my_generator():
thing_generated =True
do_work(thing)
Si eso no es lo suficientemente bueno, aún puede realizar una prueba explícita. En este punto, thingcontendrá el último valor generado. Si no se generó nada, será indefinido, a menos que ya haya definido la variable. Puede verificar el valor de thing, pero eso es poco confiable. En cambio, solo establezca una bandera dentro del bloque y verifíquela después:
ifnot thing_generated:print"Avast, ye scurvy dog!"
Esta solución intentará consumir todo el generador, por lo que será inutilizable para generadores infinitos.
Viktor Stískala
@ ViktorStískala: No entiendo tu punto. Sería tonto probar si un generador infinito produce algún resultado.
vezult
Quería señalar que su solución podría contener una interrupción en el ciclo for, porque no está procesando los otros resultados y es inútil que se generen. range(10000000)es un generador finito (Python 3), pero no necesita revisar todos los elementos para saber si genera algo.
Viktor Stískala
1
@ ViktorStískala: Entendido. Sin embargo, mi punto es este: en general, realmente desea operar en la salida del generador. En mi ejemplo, si no se genera nada, ahora lo sabes. De lo contrario, usted opera en la salida generada según lo previsto: "El uso del generador es la prueba". No es necesario realizar pruebas especiales o consumir sin sentido la salida del generador. He editado mi respuesta para aclarar esto.
vezult
8
Odio ofrecer una segunda solución, especialmente una que no usaría yo mismo, pero, si absolutamente tuviera que hacer esto y no consumir el generador, como en otras respuestas:
def do_something_with_item(item):print item
empty_marker = object()try:
first_item = my_generator.next()exceptStopIteration:print'The generator was empty'
first_item = empty_marker
if first_item isnot empty_marker:
do_something_with_item(first_item)for item in my_generator:
do_something_with_item(item)
Ahora realmente no me gusta esta solución, porque creo que no es así como se deben usar los generadores.
Me doy cuenta de que esta publicación tiene 5 años en este momento, pero la encontré mientras buscaba una forma idiomática de hacer esto, y no vi mi solución publicada. Entonces para la posteridad:
import itertools
def get_generator():"""
Returns (bool, generator) where bool is true iff the generator is not empty.
"""
gen =(i for i in[0,1,2,3,4])
a, b = itertools.tee(gen)try:
a.next()exceptStopIteration:return(False, b)return(True, b)
Por supuesto, como estoy seguro de que muchos comentaristas señalarán, esto es hacky y solo funciona en ciertas situaciones limitadas (donde los generadores están libres de efectos secundarios, por ejemplo). YMMV.
Esto solo llamará al gengenerador una vez por cada elemento, por lo que los efectos secundarios no son un problema tan grave. Pero almacenará una copia de todo lo que se ha extraído del generador a través de b, pero no a través de a, por lo que las implicaciones de la memoria son similares a simplemente ejecutar list(gen)y verificar eso.
Matthias Fripp
Tiene dos problemas. 1. Esta herramienta iterativa puede requerir un importante almacenamiento auxiliar (dependiendo de la cantidad de datos temporales que deban almacenarse). En general, si un iterador usa la mayoría o la totalidad de los datos antes de que comience otro iterador, es más rápido usar list () en lugar de tee (). 2. Los iteradores de tee no son seguros para subprocesos. Se puede generar un RuntimeError cuando se utilizan iteradores simultáneos devueltos por la misma llamada tee (), incluso si el iterable original es seguro para subprocesos.
AJ
3
Perdón por el enfoque obvio, pero la mejor manera sería hacer:
for item in my_generator:print item
Ahora ha detectado que el generador está vacío mientras lo está utilizando. Por supuesto, el elemento nunca se mostrará si el generador está vacío.
Es posible que esto no coincida exactamente con su código, pero para eso está el modismo del generador: iterar, por lo que tal vez podría cambiar su enfoque ligeramente o no usar generadores en absoluto.
O ... el interrogador podría proporcionar alguna pista de por qué uno trataría de detectar un generador vacío.
S.Lott
¿quiso decir "no se mostrará nada porque el generador está vacío"?
SilentGhost
S.Lott. Estoy de acuerdo. No puedo ver por qué. Pero creo que incluso si hubiera una razón, el problema podría ser mejor para usar cada elemento en su lugar.
Ali Afshar
1
Esto no le dice al programa si el generador estaba vacío.
Ethan Furman el
3
Todo lo que necesita hacer para ver si un generador está vacío es intentar obtener el siguiente resultado. Por supuesto, si no está listo para usar ese resultado, debe almacenarlo para devolverlo más tarde.
Aquí hay una clase de contenedor que se puede agregar a un iterador existente para agregar una __nonzero__prueba, para que pueda ver si el generador está vacío con un simple if. Probablemente también se puede convertir en un decorador.
Esto se dirige en la dirección correcta. Debe modificarse para permitir mirar hacia adelante tanto como lo desee, almacenando tantos resultados como sea necesario. Idealmente, permitiría empujar elementos arbitrarios en la cabeza de la secuencia. Un iterador presionable es una abstracción muy útil que uso a menudo.
sfkleach
@sfkleach No veo la necesidad de complicar esto para múltiples adelantos, es bastante útil como es y responde la pregunta. A pesar de que esta es una vieja pregunta, todavía tiene un aspecto ocasional, por lo que si desea dejar su propia respuesta, alguien podría encontrarla útil.
Mark Ransom
Mark tiene razón en que su solución responde a la pregunta, que es el punto clave. Debería haberlo redactado mejor. Lo que quise decir es que los iteradores empujables con retroceso ilimitado son un idioma que he encontrado extremadamente útil y la implementación es posiblemente aún más simple. Como se sugiere, publicaré el código de variante.
sfkleach
2
Impulsado por Mark Ransom, aquí hay una clase que puede usar para ajustar cualquier iterador para que pueda mirar hacia adelante, empujar los valores nuevamente en la secuencia y verificar si está vacío. Es una idea simple con una implementación simple que he encontrado muy útil en el pasado.
classPushable:def __init__(self, iter):
self.source = iter
self.stored =[]def __iter__(self):return self
def __bool__(self):if self.stored:returnTruetry:
self.stored.append(next(self.source))exceptStopIteration:returnFalsereturnTruedef push(self, value):
self.stored.append(value)def peek(self):if self.stored:return self.stored[-1]
value = next(self.source)
self.stored.append(value)return value
def __next__(self):if self.stored:return self.stored.pop()return next(self.source)
>>> g=(i for i in[])>>> g,empty=is_empty_no_side_effects(g)>>> empty
True>>> g=(i for i in range(10))>>> g,empty=is_empty_no_side_effects(g)>>> empty
False>>> list(g)[0,1,2,3,4,5,6,7,8,9]
>>> gen =(i for i in[])>>> next(gen)Traceback(most recent call last):File"<pyshell#43>", line 1,in<module>
next(gen)StopIteration
Al final del generador StopIterationse genera, ya que en su caso se alcanza el final de inmediato, se genera una excepción. Pero normalmente no debe verificar la existencia del siguiente valor.
Otra cosa que puedes hacer es:
>>> gen =(i for i in[])>>>ifnot list(gen):print('empty generator')
Lo que realmente consume todo el generador. Lamentablemente, de la pregunta no está claro si este es un comportamiento deseable o indeseable.
S.Lott
como cualquier otra forma de "tocar" el generador, supongo.
SilentGhost
Sé que esto es viejo, pero el uso de 'lista ()' no puede ser la mejor manera, si la lista generada no está vacío pero de hecho grande, entonces esto es un desperdicio innecesario
Chris_Rands
1
Si necesita saber antes de usar el generador, entonces no, no hay una manera simple. Si puede esperar hasta después de haber usado el generador, hay una manera simple:
was_empty =Truefor some_item in some_generator:
was_empty =False
do_something_with(some_item)if was_empty:
handle_already_empty_generator_case()
Simplemente envuelva el generador con itertools.chain , coloque algo que represente el final del iterable como el segundo iterable, luego simplemente verifique eso.
Use en eog = object()lugar de asumir que float('-inf')eso nunca ocurrirá en el iterable.
bfontaine
@bfontaine Buena idea
smac89
1
En mi caso lo que necesitaba saber si una gran cantidad de generadores fue poblada antes de que pasé a una función, que se fusionó los elementos, es decir, zip(...). La solución es similar, pero lo suficientemente diferente, de la respuesta aceptada:
def filter_empty(iterables):for iterable in iterables:
itr_has_items, iterable = has_items(iterable)if itr_has_items:yield iterable
def merge_iterables(iterables):
populated_iterables = filter_empty(iterables)for items in zip(*populated_iterables):# Use items for each "slice"
Mi problema particular tiene la propiedad de que los iterables están vacíos o tienen exactamente el mismo número de entradas.
Encontré solo esta solución que también funciona para iteraciones vacías.
def is_generator_empty(generator):
a, b = itertools.tee(generator)try:
next(a)exceptStopIteration:returnTrue, b
returnFalse, b
is_empty, generator = is_generator_empty(generator)
O si no desea usar una excepción para esto, intente usar
def is_generator_empty(generator):
a, b = itertools.tee(generator)for item in a:returnFalse, b
returnTrue, b
is_empty, generator = is_generator_empty(generator)
En la solución marcada no es posible usarlo para generadores vacíos como
Aquí hay un decorador simple que envuelve el generador, por lo que devuelve None si está vacío. Esto puede ser útil si su código necesita saber si el generador producirá algo antes de recorrerlo.
def generator_or_none(func):"""Wrap a generator function, returning None if it's empty. """def inner(*args,**kwargs):# peek at the first item; return None if it doesn't existtry:
next(func(*args,**kwargs))exceptStopIteration:returnNone# return original generator otherwise first item will be missingreturn func(*args,**kwargs)return inner
Uso:
import random
@generator_or_nonedef random_length_generator():for i in range(random.randint(0,10)):yield i
gen = random_length_generator()if gen isNone:print('Generator is empty')
Un ejemplo donde esto es útil es en el código de plantillas, es decir, jinja2
Esto llama a la función del generador dos veces, por lo que incurrirá en el costo de arranque del generador dos veces. Eso podría ser sustancial si, por ejemplo, la función de generador es una consulta de base de datos.
Ian Goldby
0
usando islice solo necesita verificar hasta la primera iteración para descubrir si está vacío.
de itertools import islice
def isempty (iterable):
lista de retorno (islice (iterable, 1)) == []
No podemos usar "any ()" para todo el generador. Solo traté de usarlo con un generador que contiene múltiples marcos de datos. Recibí este mensaje "El valor de verdad de un DataFrame es ambiguo". en cualquiera (my_generator_of_df)
probitaille
any(generator)funciona cuando sabe que el generador generará valores a los que se puede convertir bool: los tipos de datos básicos (por ejemplo, int, string) funcionan. any(generator)será False cuando el generador esté vacío, o cuando el generador solo tenga valores falsos; por ejemplo, si un generador va a generar 0 '' (cadena vacía) y False, seguirá siendo False. Este podría o no ser el comportamiento previsto, siempre que lo sepas :)
from cytoolz import peek
from typing importTuple,Iterabledef is_empty_iterator(g:Iterable)->Tuple[Iterable, bool]:try:
_, g = peek(g)return g,FalseexceptStopIteration:return g,True
El iterador devuelto por esta función será equivalente al original pasado como argumento.
[]
es convenientemente Falsey para que pueda hacer un chequeo y hacer un comportamiento especial para algo o nada. Los generadores son verdaderos incluso si no producen elementos.glob.iglob("filepattern")
un patrón comodín proporcionado por el usuario, y quiero advertir al usuario si el patrón no coincide con ningún archivo. Claro que puedo solucionar esto de varias maneras, pero es útil poder probar limpiamente si el iterador se quedó vacío o no.Respuestas:
La respuesta simple a su pregunta: no, no hay una manera simple. Hay muchas soluciones alternativas.
Realmente no debería haber una manera simple, debido a lo que son los generadores: una forma de generar una secuencia de valores sin mantener la secuencia en la memoria . Por lo tanto, no hay recorrido hacia atrás.
Si lo desea, puede escribir una función has_next o incluso aplicarla a un generador como método con un elegante decorador.
fuente
Sugerencia:
Uso:
fuente
return first, itertools.chain([first], rest)
.def gen(): for pony in range(4): yield None if pony == 2 else pony
None
, sino que subeStopIteration
, el resultado de la función esNone
. De lo contrario, es una tupla, que no lo esNone
.This method is for backward compatibility only. def next(self): """Return the next message in a one-time iteration.""" if not hasattr(self, '_onetime_keys'): self._onetime_keys = self.iterkeys() while True: try: return self[next(self._onetime_keys)] except StopIteration: return None except KeyError: continue
Una manera simple es usar el parámetro opcional para next () que se usa si el generador está agotado (o vacío). Por ejemplo:
Editar: corrigió el problema señalado en el comentario de mehtunguh.
fuente
object()
lugar declass
para hacerlo una línea más corta_exhausted = object()
:;if next(iterable, _exhausted) is _exhausted:
next(generator, None) is not None
O reemplazar
None
, pero cualquier valor que sabe que es no en el generador.Editar : Sí, esto saltará 1 elemento en el generador. A menudo, sin embargo, verifico si un generador está vacío solo para fines de validación, luego realmente no lo uso. O de lo contrario hago algo como:
Es decir, esto funciona si su generador proviene de una función , como en
generator()
.fuente
None
?El mejor enfoque, en mi humilde opinión, sería evitar una prueba especial. La mayoría de las veces, el uso de un generador es la prueba:
Si eso no es lo suficientemente bueno, aún puede realizar una prueba explícita. En este punto,
thing
contendrá el último valor generado. Si no se generó nada, será indefinido, a menos que ya haya definido la variable. Puede verificar el valor dething
, pero eso es poco confiable. En cambio, solo establezca una bandera dentro del bloque y verifíquela después:fuente
range(10000000)
es un generador finito (Python 3), pero no necesita revisar todos los elementos para saber si genera algo.Odio ofrecer una segunda solución, especialmente una que no usaría yo mismo, pero, si absolutamente tuviera que hacer esto y no consumir el generador, como en otras respuestas:
Ahora realmente no me gusta esta solución, porque creo que no es así como se deben usar los generadores.
fuente
Me doy cuenta de que esta publicación tiene 5 años en este momento, pero la encontré mientras buscaba una forma idiomática de hacer esto, y no vi mi solución publicada. Entonces para la posteridad:
Por supuesto, como estoy seguro de que muchos comentaristas señalarán, esto es hacky y solo funciona en ciertas situaciones limitadas (donde los generadores están libres de efectos secundarios, por ejemplo). YMMV.
fuente
gen
generador una vez por cada elemento, por lo que los efectos secundarios no son un problema tan grave. Pero almacenará una copia de todo lo que se ha extraído del generador a través deb
, pero no a través dea
, por lo que las implicaciones de la memoria son similares a simplemente ejecutarlist(gen)
y verificar eso.Perdón por el enfoque obvio, pero la mejor manera sería hacer:
Ahora ha detectado que el generador está vacío mientras lo está utilizando. Por supuesto, el elemento nunca se mostrará si el generador está vacío.
Es posible que esto no coincida exactamente con su código, pero para eso está el modismo del generador: iterar, por lo que tal vez podría cambiar su enfoque ligeramente o no usar generadores en absoluto.
fuente
Todo lo que necesita hacer para ver si un generador está vacío es intentar obtener el siguiente resultado. Por supuesto, si no está listo para usar ese resultado, debe almacenarlo para devolverlo más tarde.
Aquí hay una clase de contenedor que se puede agregar a un iterador existente para agregar una
__nonzero__
prueba, para que pueda ver si el generador está vacío con un simpleif
. Probablemente también se puede convertir en un decorador.Así es como lo usarías:
Tenga en cuenta que puede verificar el vacío en cualquier momento, no solo al comienzo de la iteración.
fuente
Impulsado por Mark Ransom, aquí hay una clase que puede usar para ajustar cualquier iterador para que pueda mirar hacia adelante, empujar los valores nuevamente en la secuencia y verificar si está vacío. Es una idea simple con una implementación simple que he encontrado muy útil en el pasado.
fuente
Simplemente caí en este hilo y me di cuenta de que faltaba una respuesta muy simple y fácil de leer:
Si se supone que no debemos consumir ningún artículo, entonces debemos reinyectar el primer artículo en el generador:
Ejemplo:
fuente
Al final del generador
StopIteration
se genera, ya que en su caso se alcanza el final de inmediato, se genera una excepción. Pero normalmente no debe verificar la existencia del siguiente valor.Otra cosa que puedes hacer es:
fuente
Si necesita saber antes de usar el generador, entonces no, no hay una manera simple. Si puede esperar hasta después de haber usado el generador, hay una manera simple:
fuente
Simplemente envuelva el generador con itertools.chain , coloque algo que represente el final del iterable como el segundo iterable, luego simplemente verifique eso.
Ex:
Ahora todo lo que queda es verificar el valor que agregamos al final del iterable, cuando lo lea, eso significará el final
fuente
eog = object()
lugar de asumir quefloat('-inf')
eso nunca ocurrirá en el iterable.En mi caso lo que necesitaba saber si una gran cantidad de generadores fue poblada antes de que pasé a una función, que se fusionó los elementos, es decir,
zip(...)
. La solución es similar, pero lo suficientemente diferente, de la respuesta aceptada:Definición:
Uso:
Mi problema particular tiene la propiedad de que los iterables están vacíos o tienen exactamente el mismo número de entradas.
fuente
Encontré solo esta solución que también funciona para iteraciones vacías.
O si no desea usar una excepción para esto, intente usar
En la solución marcada no es posible usarlo para generadores vacíos como
fuente
Esta es una pregunta vieja y respondida, pero como nadie la ha mostrado antes, aquí va:
Puede leer más aquí
fuente
Aquí está mi enfoque simple que uso para seguir devolviendo un iterador mientras verifico si se produjo algo, solo verifico si el ciclo se ejecuta:
fuente
Aquí hay un decorador simple que envuelve el generador, por lo que devuelve None si está vacío. Esto puede ser útil si su código necesita saber si el generador producirá algo antes de recorrerlo.
Uso:
Un ejemplo donde esto es útil es en el código de plantillas, es decir, jinja2
fuente
usando islice solo necesita verificar hasta la primera iteración para descubrir si está vacío.
fuente
¿Qué pasa con el uso de any ()? Lo uso con generadores y funciona bien. Aquí hay un chico explicando un poco sobre esto
fuente
any(generator)
funciona cuando sabe que el generador generará valores a los que se puede convertirbool
: los tipos de datos básicos (por ejemplo, int, string) funcionan.any(generator)
será False cuando el generador esté vacío, o cuando el generador solo tenga valores falsos; por ejemplo, si un generador va a generar 0 '' (cadena vacía) y False, seguirá siendo False. Este podría o no ser el comportamiento previsto, siempre que lo sepas :)Use la función de vistazo en cytoolz.
El iterador devuelto por esta función será equivalente al original pasado como argumento.
fuente
Lo resolví usando la función de suma. Vea a continuación un ejemplo que utilicé con glob.iglob (que devuelve un generador).
* Esto probablemente no funcionará para generadores ENORMES, pero debería funcionar bien para listas más pequeñas
fuente