2009-10-13 10 views
13

Estoy buscando una forma de invertir un objeto generador. Yo sé cómo revertir secuencias:Python Reverse Generator

foo = imap(seq.__getitem__, xrange(len(seq)-1, -1, -1)) 

Pero es algo parecido posible con un generador como la entrada y un generador invertido como la salida (len (SEC) se mantiene igual, por lo que el valor de la secuencia original puede ser usado)?

+3

Tengo que hacer una excepción con su ejemplo de invertir una secuencia. ¿Por qué no usar 'invertido'? o '.reverse'? Incluso 'seq [:: - 1]' es más claro que lo que escribiste. –

+0

Porque todos estos ejemplos crearán una nueva lista. Mi ejemplo anterior es la única forma que conozco de crear una lista sin copiarla primero. –

+0

Bueno, aprendí algo nuevo: seq [:: - 1] * does * de hecho crea una nueva lista. Vea la respuesta de expresión de mi generador para una alternativa usando índices negativos. – PaulMcG

Respuesta

19

No se puede revertir un generador de ninguna manera genérica, excepto al convertirlo en una secuencia y crear un iterador a partir de eso. Los términos posteriores de un generador no necesariamente se conocerán hasta que se hayan calculado los anteriores.

Peor aún, no puede saber si su generador alguna vez alcanzará una excepción de StopIteration hasta que lo golpee, por lo que no hay manera de saber qué será siquiera un primer término en su secuencia.

lo mejor que podría hacer sería escribir una función reversed_iterator:

def reversed_iterator(iter): 
    return reversed(list(iter)) 

EDIT: Usted podría también, por supuesto, reemplace invertido en esto con su versión iterativo basado IMAP, para salvar una creación de la lista.

+13

Estrictamente hablando, 'list (iter)' no es un * cast *, es la construcción de una lista al consumir el iter del iterador. No estoy seguro de que Python tenga funciones * cast *, al menos no en el sentido de que ese término se usa en lenguajes como C o Java. int ("100") no es un molde, y float (100) no es un molde; ambos son constructores que devuelven objetos. En C, si algo se lanza, el objeto original permanece igual. Si hicieras tal cosa en Python, podrías tomar la identificación del valor original y el valor arrojado, y serían lo mismo. En resumen: en Python, el elenco está muerto. – PaulMcG

+5

"El elenco murió": ¡bien! :) –

+2

@Paul McGuire: Estoy de acuerdo con las partes importantes de lo que ha dicho. Una liendre, sin embargo: en C, un elenco * puede * cambiar el objeto original. Si lanzas 100 para flotar, C lo cambiará a 100.0f; C no simplemente arrojará el patrón de bits 0x00000064 a la variable flotante y permitirá que se convierta en cualquier valor que esté en un flotante.En C, un elenco puede simplemente cambiar el tipo (cambiar 'int *' por 'long int *', o cambiar 'int' por' long int') o puede cambiar el valor y el tipo. C++ tiene varios operadores de conversión, incluido uno que "reinterpreta" el tipo sin cambiar el valor en absoluto. – steveha

6

reversed(list(input_generator)) es probablemente la forma más fácil.

No hay forma de obtener los valores de un generador en orden "inverso" sin reunirlos todos en una secuencia primero, porque generar el segundo elemento podría depender de que se haya generado el primero.

4

De todos modos, tiene que pasar por el generador para obtener el primer elemento, así que también puede hacer una lista. Pruebe

reversed(list(g)) 

donde g es un generador.

reversed(tuple(g)) 

funcionaría también (no revisé para ver si había una diferencia significativa en el rendimiento).