Python list comprehension - доступ к последнему созданному элементу?

Можно ли получить доступ к предыдущему элементу, сгенерированному в понимании списка.

Я работаю над некоторыми материалами для шифрования игрушек. Учитывая ключ как произвольное большое целое число, значение инициализации и список элементов в качестве сообщения для шифрования. Мне нужно, чтобы каждый элемент с предыдущим зашифрованным элементом и ключом. Будет выполняться следующий цикл.

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

Я чувствую, что должно быть возможно превратить это в понимание списка, но я не совсем уверен, как обрабатывать как начальное значение, так и доступ к предыдущему полученному значению. Возможно ли, и если да, то каким было бы понимание?

Ответы

Ответ 1

Существует не хороший, Pythonic способ сделать это со списком. Лучший способ подумать о понимании списков - это замена map и filter. Другими словами, вы должны использовать понимание списка, когда вам нужно взять список и

  • Используйте его элементы в качестве входных данных для некоторого выражения (например, возведения в квадрат элементов)

  • Удалите некоторые его элементы на основе некоторого условия

Что общего имеет эти вещи, так это то, что каждый из них смотрит только на один элемент списка за раз. Это хорошее эмпирическое правило; даже если бы вы могли теоретически написать код, который вы показали как понимание списка, это было бы неудобно и бесстрашно.

Ответ 3

Вы могли бы сделать это, используя reduce(). Это не список понимания, но это подход функционального стиля:

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

В этом случае он не более симпатичный, чем простой цикл.

Ответ 4

Как генератор:

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

list(cypher(message, key, initial_seed))

Ответ 5

Вы можете использовать вспомогательный объект для хранения всего внутреннего состояния при повторении последовательности:

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, который был сделан во время шифрования.