python中的賦值,什麼時候是傳值什麼時候是傳址?
s = [1, 2, 3]
t = st.reverse()然後s和t都變成了[3, 2, 1]但是如果s = [1, 2, 3]t = s[::-1]
只有t是[3, 2, 1] s還是[1, 2, 3]不變的...所以我比較奇怪,python中的賦值,什麼時候是傳值什麼時候是傳址?
Python一切皆為對象。賦值一直都是傳址。所有變數都是保存著對象的地址。
首先,分析一下題主所描述的兩種情況出現不同的原因。
第一種情況將s賦值給了t,此時s和t指向了同一個對象。所以執行reverse時,對象本身被改變。因為s和t指向同一個對象,所以你無論輸出s還是t都是輸出同一個已經被reverse的對象。第二種情況是對s執行了一個slicing的操作。此時本身s[::-1]返回的不是s對象本身,而是一個在內存中根據運算重新生成的對象,所以t得到的是一個s[::-1]生成的新對象的地址。而s還是保留著原來的對象,由於s[::-1]不會改變原來對象的值,所以s的值是不會改變的。再進一步。
在Python中,即使是整數類型,它也是按照對象來處理的。例如a=1,它並不是將1值賦值給了a,而是將一個整數對象1的地址賦值給了a。由於Python對小整數的特殊處理,凡是在一定範圍內的小整數,是統一使用了「小整數對象池」。也就是說所有的小整數,例如1,都是使用對象池裡面的同一個對象。但是,小整數對象池是有限的,範圍是[-5, 257) 注意左閉右開。所以,超過這個範圍的整數,嚴格來說,是需要生成這樣的一個對象的。所以,就會出現下面的情況
&>&>&> a = 1
&>&>&> b = 1
&>&>&> id(a) == id(b)
True
&>&>&> c = 1000000
&>&>&> d = 1000000
&>&>&> id(c) == id(d)
False
而整數對象是一種不可變類型,也就是說,一旦你生成了一個257的整形對象,你這個對象保存的數字就是不能再變化的了。那麼我們對整數執行加法的時候,得到的結果和原來的對象是什麼關係呢?答案是,沒關係,結果是根據求和數值產生的一個全新的對象。即使全新的對象和原來數值一樣,也是不同的對象(除非數字在小整數對象池內)。例如:
&>&>&> e = c + 0
&>&>&> id(c) == id(e)
False
&>&>&> f = a + 0
&>&>&> id(a) == id(f)
True
而列表類型是一種可變類型。他提供了一些原地改變對象而不用生成新對象的方法,例如題主的s.reverse()。但同時,也可以生成一個新的對象儲存想要的結果,例如題主的s[::-1],或者reversed(s)。PS:注意reverse()和reversed的區別
以上!=========Updates2014-11-16經 @偷窺的貓Hatori 提醒,修改了一個筆誤。2014-11-18經 @龔撝撝 提醒,修改了一個筆誤。=========
參考資料Python 源碼閱讀Python源碼--整數對象(PyIntObject)的內存池在python中, parameter sent to function 使用的全部是 by object。
也就是,這無法通過by value或者 by reference 來定義。這是python的獨到之處。如果object本身是immutable的,例如一個不是太長的整數,那麼你可以看作是傳值。因為每一次對這個object賦值,都會創建一個新的object,如下:a=10
def function1(value): value=20print(value)
function1(a)print(a)
結果是
20
10
雖然傳過去的是a這個object,但當function1對a賦值的時候,其實他並沒有改變a,而是創建了一個新的object,這個object叫做value了。global當中的a並沒有變。
如果object本身是mutable,例如一個list,因為每一次對這個object賦值,都會改變這個object本身。那麼就可以看作是傳reference。如下:
a=[10,11,12,13]
def function1(value): value[1:3]=[] print(value)function1(a)
print(a)
結果是
[10,13]
[10,13]
。。答到一半,看了下題目好像答非所問了。
題目問的問題其實更簡單。
list.reverse 是一個in-place method。也就是說,reverse是在原來object上操作,而不會創造一個新的object。上面t=s,按照python傳object的標準,那麼就是t=s 是同一個object。.reverse作用在這個object上,那麼t,s都變了。他們只是名字而已。而slicing [::] 這個,會創造一個新的object。所以。自然啦。最好的辦法是deep copy賦值只是傳址,切片的話就是copy值了
推薦閱讀:
※Stack Overflow 2016年度 20個最佳Python問題(一)
※python爬蟲之豆瓣音樂top250
※如何訓練自己的編程思路
※透過數據看 Github
※數據分析修鍊歷程:你在哪一站?
TAG:Python |