2010-09-01 85 views
5

我的Python變量發生了什麼? old_pos似乎被鏈接到posPython變量怪異?

代碼:

pos = [7, 7] 
direction = [1, 1] 
old_pos = pos 
print 'pos  = '+str(pos) 
print 'old_pos = '+str(old_pos) 
pos[0] += direction[0] 
pos[1] += direction[1] 
print 'pos  = '+str(pos) 
print 'old_pos = '+str(old_pos) 

輸出:

pos  = [7, 7] 
old_pos = [7, 7] 
pos  = [8, 8] 
old_pos = [8, 8] 

但是,如果我用old_pos = tuple(pos)甚至old_pos = list(pos)更換old_pos = pos,我不明白這個問題:

pos  = [7, 7] 
old_pos = [7, 7] 
pos  = [8, 8] 
old_pos = [7, 7] 
+2

是的,這就是'='所做的。 :-) – Ken 2010-09-01 14:57:23

+1

python中沒有變量,只有名字和對象。 – hop 2010-09-01 15:19:16

+0

@hop:但是不是名稱引用變量? – recursive 2010-09-01 15:22:26

回答

12

當您說old_pos = pos時,您並未創建pos的副本,而只是對同一列表進行另一次引用。如果您需要兩個獨立運行的列表,您需要製作一份副本,例如使用您提及的list(pos)函數或使用切片符號pos[:]

3

old_pos似乎被鏈接到pos

正確的 - 這一點:

old_pos = pos 

使得old_pospos指向同一個列表。它不會創建pos的新副本。

3

遞歸是正確的原因。你可以看到,它們具有相同的內存地址:

>>> pos = [7, 7] 
>>> old_pos = pos 
>>> id(pos) 
4299304472 
>>> id(old_pos) 
4299304472 

這就是所謂的引用傳遞,與按值傳遞。您也可以通過使用copy模塊來糾正這種情況。

>>> from copy import copy 
>>> pos = [7, 7] 
>>> old_pos = pos 
>>> id(pos) 
4299304472 
>>> id(old_pos) 
4299304472 
>>> old_pos = copy(pos) 
>>> id(old_pos) 
4299349240 
+3

嗯......它不是真的*通過引用傳遞*,因爲在示例中你不是**傳遞**任何東西。只是,Python名稱具有*引用語義*,它們如何引用Python對象。 – 2010-09-01 15:39:42

7

old_pos = pos不會產生由名字pos refered對象的副本,而是創建一個名爲old_pos到相同的對象第二參考。對pos所做的操作會影響old_pos所提及的同一對象。同樣,「Steven」和「Rumbalski先生」這兩個名字都指向我。如果你在臉上猛擊史蒂芬,魯巴爾斯基先生會受傷,因爲這兩個名字都指向同一個對象 - 我。

這裏有3種方式提供的實際副本,而不是第二個參考:

使用切片表示法

old_pos = pos[:] 

使用列表構造

old_pos = list(pos) 

使用拷貝模塊

from copy import copy 
old_pos = copy(pos) 

注意,這些副本都是淺拷貝,在這種情況下是罰款。要了解淺拷貝和深拷貝之間的區別,請閱讀documentation of the copy module

+0

+1優秀的隱喻。 – 2010-09-01 15:38:30

0

除了上述評論之外,在多維數組情況下必須採取一些額外的步驟。例如,當您有一個二維數組a = [[0,1,2],[3,4],[5,6,7,8]]時,代碼b = a將不會創建獨立副本。但是,它會在二維列表中創建另一個引用同一維列表的引用。爲了解決這個問題,你必須爲二維列表中的每個列表使用上述方法之一。例如,b = [i[:] for i in a]將創建列表的獨立副本。