Python list comprehension - access last created element?

后端 未结 7 1996
无人共我
无人共我 2020-12-14 17:31

Is it possible to access the previous element generated in a list comprehension.

I am working on some toy encryption stuff. Given the key as an arbitrarily large in

相关标签:
7条回答
  • 2020-12-14 18:16

    You could have done this using reduce(). It's not list comprehension, but it's the functional style approach:

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

    It isn't any prettier than the plain loop in this case though.

    0 讨论(0)
  • 2020-12-14 18:20

    I would prefer to use something more like enumerate generator

    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)
    
    0 讨论(0)
  • 2020-12-14 18:21

    There isn't a good, Pythonic way to do this with a list comprehension. The best way to think about list comprehensions is as a replacement for map and filter. In other words, you'd use a list comprehension whenever you need to take a list and

    • Use its elements as input for some expression (e.g. squaring the elements)

    • Remove some of its elements based on some condition

    What these things have in common is that they each only look at a single list element at a time. This is a good rule of thumb; even if you could theoretically write the code you showed as a list comprehension, it would be awkward and unpythonic.

    0 讨论(0)
  • 2020-12-14 18:21

    It probably can be done; see The Secret Name of List Comprehensions. It's very much not pythonic, though.

    0 讨论(0)
  • 2020-12-14 18:22

    As a generator:

    def cypher(message, key, seed):
        for element in message:
            seed = element ^ seed ^ key
            yield seed
    
    list(cypher(message, key, initial_seed))
    
    0 讨论(0)
  • 2020-12-14 18:27

    You could use a helper object to store all the internal state while iterating over the sequence:

    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]
    

    That being said, adding the previously encrypted element into the xor doesn't make your algorithm any harder to break than just xor'ing every element with the key. An attacker can just xor any character in the cipher text with the previous encrypted character and so cancel out the xor that was done during encryption.

    0 讨论(0)
提交回复
热议问题