2010-06-17 109 views
27

我在Python 2.6.5中有一個奇怪的問題,使用Numpy。我分配一個numpy數組,然後將一個新變量等同於它。當我對新陣列執行任何操作時,原始值也會改變。這是爲什麼?請看下面的例子。請賜教,因爲我對Python相當陌生,而且一般編程。numpy數組賦值問題

-Sujan

>>> import numpy as np 
>>> a = np.array([[1,2],[3,4]]) 
>>> b = a 
>>> b 
array([[1, 2], 
     [3, 4]]) 
>>> c = a 
>>> c 
array([[1, 2], 
     [3, 4]]) 
>>> c[:,1] = c[:,1] + 5 
>>> c 

array([[1, 7], 
     [3, 9]]) 
>>> b 
array([[1, 7], 
     [3, 9]]) 
>>> a 
array([[1, 7], 
     [3, 9]]) 

回答

56

這實際上不是在所有問題;這是數組(和其他對象)在Python中工作的方式。

想想這樣:你在你的代碼示例中創建的數組是一個對象,它位於內存中的某個位置。但是你不能在你的程序中使用它來告訴Python在內存中的哪個地方去尋找它;你必須給它一個名字。當你寫

a = np.array([[1,2],[3,4]]) 

你都創建陣列並創建一個名稱,a,是指它。從那時起,Python知道a引用「內存地址0x123674283」(或其他)。有一個在Python運行時的內部表(稱爲「符號表」如果我沒有記錯),它包含所有這些信息,所以Python代碼上線運行後,該表將包含

..., 
'a' : 0x123674283, 
... 

當您指定一個變量的另一個值,如

b = a 

Python不復制整個陣列,因爲如果它是一個大的陣列,它需要很長的時間。相反,它進入符號表並將a的內存地址複製到b表中的新行。所以,你風與

..., 
'a' : 0x123674283, 
..., 
'b' : 0x123674283, 
... 

所以你看,ab實際上指的是同一個內存位置,即同一個對象。你對一個人所做的任何更改都會反映在另一個人的身上,因爲他們只是兩個同名的人物。

如果你想實際製作一個數組的副本,你必須調用一個方法來明確地做到這一點。 Numpy數組有一個copy方法,您可以將其用於此目的。所以,如果你寫

b = a.copy() 

那麼Python會先實際上使數組的副本 - 也就是說,它留出一個新的內存區域,讓我們在地址0x123904381​​說,然後去到內存地址0x123674283,並將所有從後一段內存到前一段的數組值。所以你有相同的內容坐在記憶中的兩個不同的地方。

..., 
'a' : 0x123674283, 
..., 
'b' : 0x123904381, 
... 

現在,當你改變的b的要素之一,這種變化不會在a露面,因爲ab不再指的是計算機內存的同一節。由於陣列數據有兩個獨立的副本,因此您可以更改一個,而不會影響另一個。

+6

非常感謝你的出色描述。不用說,這解決了問題,但我真的很感謝你花時間來解釋事情。你開悟了我! – Sujan 2010-06-17 16:29:49

+1

「Python不會複製整個數組,因爲如果它是一個大數組,它將需要很長時間。」 - 我會說它不太需要它花費的時間,更多的是如果你不以這種方式實現事情,你需要引入類似單獨的指針類型和那些複雜的東西。 – user2357112 2017-04-29 15:57:17

1

簡而言之,變量賦值會創建對現有對象的新引用。

A = object # A points to object in memory 
    B = A  # B points to the same object