¿Hay una expresión para un generador infinito?

¿Existe una expresión generadora directa que pueda producir elementos infinitos?

Esta es una cuestión puramente teórica. No hay necesidad de una respuesta “práctica” aquí 🙂


Por ejemplo, es fácil hacer un generador finito:

my_gen = (0 for i in xrange(42)) 

Sin embargo, para hacer uno infinito necesito “contaminar” mi espacio de nombres con una función falsa:

 def _my_gen(): while True: yield 0 my_gen = _my_gen() 

Hacer cosas en un archivo separado e import más tarde no cuenta.


También sé que itertools.repeat hace exactamente esto. Tengo curiosidad si hay una solución de una sola línea sin eso.

 for x in iter(int, 1): pass 
  • Iter de dos argumentos = argumento cero llamable + valor de centinela
  • int() siempre devuelve 0

Por lo tanto, iter(int, 1) es un iterador infinito. Obviamente, hay un gran número de variaciones sobre este tema en particular (especialmente una vez que agregas lambda a la mezcla). Una variante de una nota en particular es iter(f, object()) , ya que usar un objeto recién creado como valor de centinela casi garantiza un iterador infinito, independientemente del que se pueda llamar como primer argumento.

itertools proporciona tres generadores infinitos:

  • count(start=0, step=1) : 0, 1, 2, 3, 4, …

  • cycle(p) : p [0], p [1], …, p [-1], p [0], …

  • repeat(x, times=∞) : x, x, x, x, …

No sé de ningún otro en la biblioteca estándar.


Desde que pediste una sola línea:

 __import__("itertools").count() 

puede iterar sobre un llamable devolviendo una constante siempre diferente al centinela de iter ()

 g1=iter(lambda:0,1) 

Su sistema operativo puede proporcionar algo que se puede utilizar como un generador infinito. Por ejemplo en linux

 for i in (0 for x in open('/dev/urandom')): print i 

Obviamente esto no es tan eficiente como

 for i in __import__('itertools').repeat(0) print i 

Ninguno que no use internamente otro iterador infinito definido como una clase / función / generador (no -expresión, una función con yield ). Una expresión generadora siempre se basa en un marcador iterable y no hace más que filtrar y mapear sus elementos. No puede pasar de elementos finitos a infinitos con solo map y filter , necesita while (o un for que no termine, que es exactamente lo que no podemos usar solo for iteradores finitos).

Trivia: PEP 3142 es superficialmente similar, pero al inspeccionarlo más de cerca, parece que aún requiere la cláusula for (por lo que no (0 while True) ), es decir, solo proporciona un atajo para itertools.takewhile .

Bastante feo y loco (sin embargo, muy divertido), pero puedes crear tu propio iterador a partir de una expresión usando algunos trucos (sin “contaminar” tu espacio de nombres según sea necesario):

 { print("Hello world") for _ in (lambda o: setattr(o, '__iter__', lambda x:x) or setattr(o, '__next__', lambda x:True) or o) (type("EvilIterator", (object,), {}))() } 

Tal vez podrías usar decoradores como este, por ejemplo:

 def generator(first): def wrap(func): def seq(): x = first while True: yield x x = func(x) return seq return wrap 

Uso (1):

 @generator(0) def blah(x): return x + 1 for i in blah(): print i 

Uso (2)

 for i in generator(0)(lambda x: x + 1)(): print i 

Creo que podría mejorarse aún más para deshacerse de esos feos () . Sin embargo, depende de la complejidad de la secuencia que desee poder crear. En términos generales, si su secuencia puede expressse utilizando funciones, toda la complejidad y el azúcar sintáctica de los generadores pueden ocultarse dentro de un decorador o una función similar a un decorador.