2009-04-27 9 views
13

Est-il possible d'accéder à l'élément précédent généré dans une liste de compréhension. Je travaille sur des trucs de cryptage de jouets. Étant donné la clé comme un entier arbitrairement grand, une valeur d'initialisation et une liste d'éléments comme le message à chiffrer. J'ai besoin de xor chaque élément avec l'élément chiffré précédent et la clé. La boucle suivante ferait l'affaire.Compréhension de liste Python - accès dernier élément créé?

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

je me sens comme il devrait être possible de transformer cela en une compréhension de la liste mais je ne sais pas exactement comment gérer à la fois la valeur initiale ou l'accès à la valeur précédente générée. Est-ce possible et si oui, quelle serait la compréhension?

Répondre

14

Il n'y a pas une bonne façon, Pythonic, de le faire avec une compréhension de liste. La meilleure façon de penser à la compréhension des listes est de remplacer map et filter. En d'autres termes, vous utiliseriez une compréhension de liste chaque fois que vous devez prendre une liste et

  • Utilisez ses éléments en entrée pour une expression (par exemple, mise au carré des éléments)

  • Retirez certains de ses éléments selon une condition

ce que ces choses ont en commun est que chacun ne regard sur un élément de liste unique à la fois. C'est une bonne règle générale. même si vous pouviez théoriquement écrire le code que vous avez montré comme une compréhension de liste, ce serait maladroit et non pythonique.

+5

+1: C'est pourquoi nous avons encore pour la déclaration - pour les situations exactement comme cette question. –

1

Vous pouvez utiliser un objet d'aide pour stocker tout l'état interne tout en évoluant sur la séquence:

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] 

Cela étant dit, en ajoutant l'élément chiffré précédemment dans le XOR ne rend pas votre algorithme plus dur à casser que juste xor'ing chaque élément avec la clé. Un attaquant peut simplement xoriser n'importe quel caractère dans le texte chiffré avec le caractère crypté précédent et donc annuler le xor qui a été fait pendant le cryptage.

3

Vous auriez pu faire cela en utilisant reduce(). Il est la liste non compréhension, mais il est l'approche de style fonctionnel:

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

Il est pas plus jolie que la boucle ordinaire dans ce cas cependant.

+1

Vérifiez la performance avant d'utiliser réduire; cela peut souvent conduire à des structures remarquablement inefficaces. –

+1

La version «for loop» est * beaucoup * plus propre, donc ne traitez cette réponse que comme «théoriquement possible de faire autrement». –

3

En tant que générateur:

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

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

J'aime cette solution même si ce n'est pas ce que demande OP. – MaLiN2223

Questions connexes