是否可以访问列表推导中生成的前一个元素。
我正在研究一些玩具加密的东西。将密钥作为任意大整数,初始化值和元素列表作为要加密的消息。我需要使用先前的加密元素和密钥对每个元素进行xor。以下循环可以。
previous = initialization_value
cipher = []
for element in message:
previous = element ^ previous ^ key
cipher.append(previous)
我觉得应该可以将其转换为列表理解,但我不确定如何处理初始值或访问生成的先前值。 是否有可能,如果是这样,那么理解是什么?
答案 0 :(得分:15)
用列表理解来做这个没有好的Pythonic方法。考虑列表推导的最佳方式是替换map
和filter
。换句话说,只要你需要列表和
使用其元素作为某些表达式的输入(例如,对元素进行平方)
根据某些条件删除部分内容
这些东西的共同之处在于它们每次只能查看一个列表元素。这是一个很好的经验法则;即使你理论上可以把你所展示的代码写成列表理解,它也会很笨拙而且是单一的。
答案 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()分析函数非常相似。