Python列表理解 - 访问最后创建的元素?

时间:2009-04-27 18:46:28

标签: python

是否可以访问列表推导中生成的前一个元素。

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

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

我觉得应该可以将其转换为列表理解,但我不确定如何处理初始值或访问生成的先前值。 是否有可能,如果是这样,那么理解是什么?

7 个答案:

答案 0 :(得分:15)

用列表理解来做这个没有好的Pythonic方法。考虑列表推导的最佳方式是替换mapfilter。换句话说,只要你需要列表和

,就可以使用列表推导
  • 使用其元素作为某些表达式的输入(例如,对元素进行平方)

  • 根据某些条件删除部分内容

这些东西的共同之处在于它们每次只能查看一个列表元素。这是一个很好的经验法则;即使你理论上可以把你所展示的代码写成列表理解,它也会很笨拙而且是单一的。

答案 1 :(得分:4)

可能可以做到;见The Secret Name of List Comprehensions。但是,它不是pythonic。

答案 2 :(得分:3)

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

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

虽然在这种情况下它并不比普通循环更漂亮。

答案 3 :(得分:3)

作为发电机:

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

list(cypher(message, key, initial_seed))

答案 4 :(得分: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中并不会使您的算法更难破解,而不仅仅是使用键对每个元素进行xor'ing。攻击者可以使用先前加密的字符对密文中的任何字符进行xor,因此取消加密期间完成的xor。

答案 5 :(得分:0)

我更喜欢使用enumerate生成器

def emit_previous(iterable, initial=None):
    previous = initial
    for item in iterable:
        yield previous, item
        previous = item

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

答案 6 :(得分:0)

这里是一个示例,该示例如何使用枚举访问列表理解中的上一个和下一个创建的元素。

上一个值...

这里-1是偏移量,而None是默认值。

A = ['A','B','C','D','E','F','G','H','I','J']
[(A[i-1] if (i-1) >= 0 else None,x) for i,x in enumerate(A)

输出为元组(上一个,当前)

[(无,'A'), (“ A”,“ B”), (“ B”,“ C”), (“ C”,“ D”), (“ D”,“ E”), (“ E”,“ F”), (“ F”,“ G”), (“ G”,“ H”), (“ H”,“ I”), (“我”,“ J”)]

下一个值...

A = ['A','B','C','D','E','F','G','H','I','J']
[(x, A[i+1] if (i+1) < len(A) else None) for i,x in enumerate(A)]

输出为元组(当前,下一个)

[('A','B'), (“ B”,“ C”), (“ C”,“ D”), (“ D”,“ E”), (“ E”,“ F”), (“ F”,“ G”), (“ G”,“ H”), (“ H”,“ I”), (“我”,“ J”), (“ J”,无)]

这与sql中的lag()和lead()分析函数非常相似。