2009-04-27 58 views
13

是否可以访问在列表理解中生成的前一个元素。Python列表理解 - 访问最后创建的元素?

我正在做一些玩具加密的东西。将密钥作为任意大的整数,初始化值和元素列表作为要加密的消息。我需要用先前的加密元素和密钥对每个元素进行异或。下面的循环会做。

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

我觉得它应该有可能变成一个列表理解,但我不完全知道如何处理这两个初始值或访问产生的前值。 是否有可能,如果是的话,理解是什么?

回答

14

没有一个好的Pythonic方法来做到这一点与列表理解。考虑列表解析的最佳方式是替代mapfilter。换句话说,你会使用一个列表理解时,你需要采取的列表,并

  • 使用它的元素作为输入一些表达(如平方元素)

  • 删除某些内容的基于一些条件

这些事情的共同之处在于它们每次只能查看单个列表元素。这是一个很好的经验法则;即使你理论上可以将你所显示的代码编写成一个列表理解,但它会是尴尬和不合理的。

+5

+1:这就是为什么我们仍然有for语句 - 用于酷似这个问题的情况。 – 2009-04-27 19:48:44

1

你可以使用一个辅助对象来存储所有的内部状态,而遍历序列:

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] 

话虽这么说,以前加密的元素到XOR不会使你的算法任何更难而不是仅仅用关键字敲击每个元素。攻击者可以使用先前的加密字符对密文中的任何字符进行异或,从而抵消在加密过程中完成的异或。

3

您可以使用reduce()来完成此操作。这不是列表理解,但它是功能风格的方法:

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

它在这种情况下没有任何比普通循环更漂亮。

+1

使用前检查性能减少;它通常会导致显着低效的结构。 – 2009-04-27 20:30:55

+1

'for循环'版本* *更清洁,因此只将这个答案看作是“理论上可能做不到的事情”。 – 2009-04-28 07:12:35

3

作为发电机:

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

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

即使不是OP要求的,我也喜欢这个解决方案。 – MaLiN2223 2016-12-13 10:46:00