2010-11-17 56 views
3

我似乎無法爲這個地方找到一個解釋......爲什麼Python中的for ... in ...語句中的元素使用byValue行爲?

假設我有初始化爲全零向量y:

from numpy import * 
y = zeros(5) 

它也可能是一個普通的Python陣列,我不我認爲它確實很重要。

我注意到for x in y:語句的行爲是它使y中每個元素的拷貝,因此當你修改x時,它不會修改y。

for x in y: 
    x = 1 
print y 

output : array([ 0., 0., 0., 0., 0.]) 

我的問題如下:爲什麼這樣?我認爲在Python中,所有的東西都是引用的,並且傳遞的值很少?

我怎樣才能做到以下幾點,使用引用的變量?執行以下似乎工作:

for i in range(len(y)): 
    y[i] = 2*rand()-1 

但是,從我瞭解的Python,這是錯誤的我相信這將是緩慢的,當我開始使用的值十萬或數百萬的載體。

我還能做什麼?

y = np.zeros(5) 
for i in range(len(y)): 
    y[i] = 2*rand()-1 

與:

回答

8

可以替換此

y=2*np.random.rand(5)-1 

如果y一個Python序列(元組,列表,陣列等)或numpy的陣列,

for x in y:

重複通過y,將x設置爲y中的每個元素。 如果元素是不可變對象,如str,int,float或Numpy數字類型 ,則更改x的值不會更改y中的值。

如果元素是可變對象,例如list,則變異list將影響y

考慮一下這種方式:x的「指點」的一個對象:

y---> [o----o----o----o] 
      ^
      | 
      x 

當你寫一個賦值語句:

x += 1 

現在你重新分配x爲「點」不同的對象:

y---> [o----o----o----o] 

x---> o 

另一方面,如果喲ü用x.append(1)變異列表,然後 x仍然指向同一對象(例如,一個列表),但是你已經改變了該列表的內容。

0

我看不出代碼示例是如何錯誤的 - 只要y可以從for循環所在的範圍訪問,那麼應該都是好的。

4

Python 確實只使用「引用」。但Python中的所謂「引用」(和Java,以及其他一些語言)與「傳遞引用」或「C++中的引用」不同。當您迭代諸如for i in iterable:,i之類的東西時指向當前項目。但是,如果在循環中執行i = ...,則會覆蓋該引用而不是替換指向的對象。實際上,Python(以及所提及的所有其他語言)都是按值傳遞的。除了這些值是總是(種)指針。

請注意,這不適用於i.attr = ...!設置成員是不同的,這是一個方法調用(對象的__dict__.__setattr__.__setattribute__ afaik的.__setitem__之一)。所以如果你在循環中做了i.some_member,你確實會改變iterable的項目。另外請注意,這當然與數字或字符串等不可變對象有關 - 你不可能改變它們。

如果你想改變例如直接列表,你需要使用指數(雖然你不應該需要range(len(...)),你可以使用enumerate(the_list),你會得到指數當前項目)。也可以考慮通過使用例如第一位來產生你想要的值。列表理解。

+0

太棒了,我一直在尋找像枚舉相當一段時間的東西:D – levesque 2010-11-17 18:22:54

1

請有人糾正我,如果我錯了,但在Python中的整數類型是不可變的,這就是爲什麼當您對向量的元素之一執行一些操作時,你得到一個新的對象。我找了又找,但沒有找到這個預感的任何確認,但是當我嘗試

>>> def zeros(length): 
...  vector = [] 
...  for each in range(length): 
...   vector.append([0]) 
...  return vector 
... 
>>> zeros(8) 
[[0], [0], [0], [0], [0], [0], [0], [0]] 
>>> y = zeros(8) 
>>> for x in y: 
...  x[0] += 1 
... 
>>> y 
[[1], [1], [1], [1], [1], [1], [1], [1]] 

,我們知道list是可變的,我們得到了我們的期望。

+0

有趣。其他人是否可以確認這是乾淨和安全的使用? – levesque 2010-11-17 18:21:27

相關問題