Lista de comprensiones en Python con estado mutable entre iteraciones

Tengo algo que es muy parecido a una lista de comprensión en Python, excepto que comparte un estado mutable entre iteraciones. ¿Hay alguna manera de hacerlo con una lista de comprensión?

def f(x): """ 5-bit LFSR """ return (x >> 1) ^ (0x12*(x&1)) def batch(f, x, n): result = [x] for _ in xrange(1,n): x = f(x) result.append(x) return result batch(f, 1, 5) 

que devuelve [1, 18, 9, 22, 11] . Aquí lo importante es la función de proceso por batch , no f(x) que es solo un ejemplo sencillo para ilustrar el problema.

Alternativamente podría implementar usando un generador:

 def batch(f, x, n): yield x for _ in xrange(1,n): x = f(x) yield x list(batch(f, 1, 5)) 

Pero huele un poco incómodo. Lo que estoy buscando es algo como esto …

 batch = [??? for _ in xrange(n)] 

No. Deliberadamente no. Finalmente, ponen en itertools.accumulate , que es lo más parecido a una forma oficialmente recomendada de implementar relaciones de recurrencia de una manera funcional, pero no existe en 2.7. Si lo desea, puede copiar la implementación de Python “aproximadamente equivalente a” de los documentos .

¿Hay alguna manera de hacerlo con una lista de comprensión?

Lo que estoy buscando es algo como esto …

 batch = [??? for _ in xrange(n)] 

Claro, no hay problema

 >>> x = 1 >>> n = 5 >>> [prev.append(f(prev[0])) or prev.pop(0) for prev in [[x]] for _ in xrange(n)] [1, 18, 9, 22, 11] 

Nota: Esta es una mala idea. (Yo solo hice esto porque el usuario2357112 dijo que no hay manera)

Puede hacer esto en una sola línea, utilizando, por ejemplo, reduce (o functools.reduce en Python 3):

 >>> f = lambda x: (x >> 1) ^ (0x12*(x&1)) >>> x, n = 1, 5 >>> functools.reduce(lambda lst, _: lst + [f(lst[-1])], range(1, n), [x]) [1, 18, 9, 22, 11] 

Pero esto no solo es feo, sino también ineficiente, ya que creará una nueva lista en cada iteración. O de manera similar al enfoque de Stefan, sin crear listas intermedias:

 >>> functools.reduce(lambda lst, _: lst.append(f(lst[-1])) or lst, range(1, n), [x]) [1, 18, 9, 22, 11] 

O, como ya se indicó en la otra respuesta, puede usar itertools.accumulate , que es mucho mejor, pero aún así es un mal uso, ya que en realidad se espera una función binaria, mientras que aquí no utilizamos el segundo parámetro, ni el iterable real pasado a la función, a excepción del primer valor.

 >>> list(itertools.accumulate([x] * n, lambda y, _: f(y))) [1, 18, 9, 22, 11]