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

nc1teljy  于 2023-01-19  发布在  Python
关注(0)|答案(9)|浏览(102)

是否可以访问列表解析中生成的前一个元素。
我正在做一些玩具加密的东西。给定一个任意大的整数作为密钥,一个初始化值,和一个元素列表作为要加密的消息。我需要将每个元素与前面加密的元素和密钥进行异或。下面的循环就可以了。

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

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

kt06eoxx

kt06eoxx1#

对于列表解析,没有一种好的、Python式的方法来实现这一点。考虑列表解析的最佳方式是将其作为mapfilter的替代。换句话说,无论何时需要获取列表和

  • 将其元素用作某个表达式的输入(例如,将元素平方)
  • 根据某些条件删除它的某些元素

它们的共同之处在于它们每次只查看一个列表元素,这是一个很好的经验法则;即使从理论上讲,您可以将所显示的代码编写为列表解析,它也会很笨拙和冗长。

hfsqlsce

hfsqlsce2#

作为发电机:

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

list(cypher(message, key, initial_seed))
wlsrxk51

wlsrxk513#

你可以使用reduce()来完成这个任务,它不是列表解析,而是函数式的方法:

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

不过,在本例中,它并不比普通循环漂亮。

0x6upsns

0x6upsns4#

下面是一个如何使用enumerate访问列表解析中最后一个和下一个创建的元素的示例。

上一个值...

此处-1是偏移,“无”是默认值。

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”)、(“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”)、(“I”、“J”)、(“J”,无)]
这与SQL中的lag()和lead()分析函数非常相似。

j8ag8udp

j8ag8udp5#

你可以使用一个helper对象来存储序列迭代时的所有内部状态:

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]

也就是说,将先前加密的元素添加到异或运算中并不会使你的算法比将每个元素与密钥进行异或运算更难被破解,攻击者可以将密文中的任何字符与先前加密的字符进行异或运算,从而抵消加密过程中进行的异或运算。

qxgroojn

qxgroojn6#

我更喜欢使用类似于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)
klsxnrf1

klsxnrf17#

因此,您可以在列表解析中向列表添加元素,并使用最后添加的元素作为该列表解析的新元素,然后最后将该解析赋值给列表变量。

message = [0,1,2,3,4,5,6,7]
key = 8
previous = 9

cipher = [previous]

cipher = [(cipher.append(element^cipher[-1]^key), cipher[-1])[1] for element in message]

print(cipher)
nnt7mjpx

nnt7mjpx8#

从Python 3.8开始,现在支持assignment expression,它可以用来实现一个列表解析,记住迭代中的最后一个值:

previous = initialization_value
cipher = [previous := element ^ previous ^ key for element in message]

如果你喜欢把所有内容都写在一行中,你可以在一个单例列表中初始化previous,然后用and操作符将其丢弃,让列表解析接管:

cipher = [previous := initialization_value] and [previous := element ^ previous ^ key for element in message]
wmomyfyw

wmomyfyw9#

itertools.accumulate()的存在正是为了:

from itertools import accumulate
result = list(accumulate(message, lambda prev, element: prev^element^key), initial=initialization_value)
del result[0] # Remove the initialization value

简单的一行程序,不需要理解或任何复杂的东西。

相关问题