2010-08-14 67 views
2
tokens_raw = {"foo": "bar"} 
tokens_raw_old = { } 
while not tokens_raw == tokens_raw_old: 
    tokens_raw_old = tokens_raw 
    # while loop that modifies tokens_raw goes here; 
    # tokens_raw_old is never referenced 
    print tokens_raw_old == tokens_raw 

這第一次因爲某些原因後,輸出真。 tokens_raw_oldtokens_raw具有相同的數據,即使單獨修改了tokens_raw也是如此。我在某個地方犯了一個愚蠢的錯誤,還是問題出在第二個while循環內(這又是一次引用tokens_raw_old)?如果沒有明顯的錯誤,我會發布更多的代碼。爲什麼這個變量被改變了?

回答

7

tokens_raw_old = tokens_raw意思是:創建一個名爲token_raw_old相同對象,該名tokens_raw是指在這個時候新的參考。這是對象的相同對象,副本!因此,通過其中一個引用對這個唯一對象所做的更改顯然也會在通過另一個引用進行檢查時影響同一個對象。

如果你要一個副本,索要一份!例如,由於tokens_raw是不可變值的字典(和鑰匙,但是這經常在類型的字典):

tokens_raw_old = tokens_raw.copy() 

就足夠了。相同的(只是個風格問題),所以會

tokens_raw_old = dict(tokens_raw) 

(通過「呼叫類型的複製構造函數」進行復制,即呼籲C++程序員的一個概念 - 它的我,所以我真的很喜歡這種形式;-)。

如果您需要支付一般情況下(tokens_raw存在許多可能的不同類型,或在它的值被也許修改):

import copy 

tokens_raw_old = copy.deepcopy(tokens_raw) 

這可以說是相當緩慢的,但是,「當你需要它,你需要它」 - 它使物體的副本,也就是說,它不只是複製容器也全部包含的對象(遞歸,如果容器包含其它容器 - 說三次快速...;-)。

並不是每一個對象都可以被複制(深或淺) - 例如,一個打開的文件對象無法複製(你需要其他的方法,如果你有這樣的怪異,高級需求)。但是,對於一個字符串作爲鍵和值的字典,我在這個答案開始時提到的簡單方法就足夠了,而且速度也很快;-)。

+0

我實際上在我粘貼的代碼中犯了一個錯誤; tokens_raw是一個列表,而不是一個字典,所以.copy()不是一個有效的方法。然而,這個迴應仍然是有道理的,我發現使用'tokens_raw_old = tokens_raw [:]'具有和你所建議的相同的效果。謝謝您的幫助。 :) – Fraxtil 2010-08-14 03:20:23

+1

@Fraxtil,肯定的,但我個人厭惡日益流行的'somelist [:]'成語 - '名單(somelist)'就是** **這樣的方式來更可讀淺複製清單(或者就此而言,製作任何輸入序列的列表版本)。啊,風格問題,我想! - ) – 2010-08-14 03:22:30