2009-04-27 22 views
13

Es posible acceder al elemento anterior generado en una lista de comprensión.Comprensión de la lista Python: ¿acceso al último elemento creado?

Estoy trabajando en algunas cosas de encriptación de juguetes. Dada la clave como un entero arbitrariamente grande, un valor de inicialización y una lista de elementos como el mensaje para encriptar. Necesito xor cada elemento con el elemento cifrado anterior y la clave. El siguiente ciclo sería suficiente.

previous = initialization_value 
cipher = [] 
for element in message: 
    previous = element^previous^key 
    cipher.append(previous) 

me siento como debería ser posible convertir esto en una lista por comprensión, pero no estoy muy seguro de cómo manejar tanto el valor inicial o acceder al valor anterior generado. ¿Es posible y, en caso afirmativo, cuál sería la comprensión?

Respuesta

14

No hay una buena manera, Pythonic para hacer esto con una lista de comprensión. La mejor manera de pensar acerca de las listas de comprensión es como un reemplazo para map y filter. En otras palabras, tendrá que utilizar una lista por comprensión cada vez que necesita para tomar una lista y

  • utilizar sus elementos como entrada para alguna expresión (por ejemplo, elevar al cuadrado los elementos)

  • eliminar algunos de sus elementos sobre la base de alguna condición

Lo que estas cosas tienen en común es que cada uno sólo vistazo a un solo elemento de la lista a la vez. Esta es una buena regla de oro; incluso si teóricamente pudieras escribir el código que mostrabas como una lista de comprensión, sería incómodo y antiponético.

+5

+1: Es por eso que aún tenemos la instrucción for - para situaciones exactamente iguales a esta pregunta. –

1

Se puede usar un objeto auxiliar para almacenar todo el estado interno, mientras que la iteración en la secuencia:

class Encryption: 
    def __init__(self, key, init_value): 
    self.key = key 
    self.previous = init_value 
    def next(self, element): 
    self.previous = element^self.previous^self.key 
    return self.previous 

enc = Encryption(...) 
cipher = [enc.next(e) for e in message] 

Dicho esto, añadiendo el elemento cifrada previamente en el xor no hace que su algoritmo con más fuerza a romper que simplemente xor'ing cada elemento con la clave. Un atacante puede simplemente anotar cualquier carácter en el texto de cifrado con el carácter encriptado anterior y cancelar así el xor que se realizó durante el cifrado.

3

Podrías haber hecho esto usando reduce(). No es una lista de comprensión, pero es el enfoque de estilo funcional:

cipher = [] 
def f(previous, element): 
    previous = element^previous^key 
    cipher.append(previous) 
    return previous 
reduce(f, message, initialization_value) 

No es más bonito que la llanura del bucle en este caso, sin embargo.

+1

Compruebe el rendimiento antes de usar reducir; a menudo puede conducir a estructuras notablemente ineficientes. –

+1

La versión 'for loop' es * mucho * más limpia, por lo tanto, trate esta respuesta solo como "teóricamente posible hacer otra cosa". –

3

Como generador:

def cypher(message, key, seed): 
    for element in message: 
     seed = element^seed^key 
     yield seed 

list(cypher(message, key, initial_seed)) 
+0

Me gusta esta solución aunque no sea lo que OP me pidió. – MaLiN2223

Cuestiones relacionadas