2009-04-27 72 views
13

是否可以訪問在列表理解中生成的前一個元素。Python列表理解 - 訪問最後創建的元素?

我正在做一些玩具加密的東西。將密鑰作爲任意大的整數,初始化值和元素列表作爲要加密的消息。我需要用先前的加密元素和密鑰對每個元素進行異或。下面的循環會做。

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

我覺得它應該有可能變成一個列表理解,但我不完全知道如何處理這兩個初始值或訪問產生的前值。 是否有可能,如果是的話,理解是什麼?

回答

14

沒有一個好的Pythonic方法來做到這一點與列表理解。考慮列表解析的最佳方式是替代mapfilter。換句話說,你會使用一個列表理解時,你需要採取的列表,並

  • 使用它的元素作爲輸入一些表達(如平方元素)

  • 刪除某些內容的基於一些條件

這些事情的共同之處在於它們每次只能查看單個列表元素。這是一個很好的經驗法則;即使你理論上可以將你所顯示的代碼編寫成一個列表理解,但它會是尷尬和不合理的。

+5

+1:這就是爲什麼我們仍然有for語句 - 用於酷似這個問題的情況。 – 2009-04-27 19:48:44

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不會使你的算法任何更難而不是僅僅用關鍵字敲擊每個元素。攻擊者可以使用先前的加密字符對密文中的任何字符進行異或,從而抵消在加密過程中完成的異或。

3

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

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

它在這種情況下沒有任何比普通循環更漂亮。

+1

使用前檢查性能減少;它通常會導致顯着低效的結構。 – 2009-04-27 20:30:55

+1

'for循環'版本* *更清潔,因此只將這個答案看作是「理論上可能做不到的事情」。 – 2009-04-28 07:12:35

3

作爲發電機:

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

list(cypher(message, key, initial_seed)) 
+0

即使不是OP要求的,我也喜歡這個解決方案。 – MaLiN2223 2016-12-13 10:46:00