1. 程式人生 > >Python中的可變,不可變物件;值型別,引用型別;淺拷貝,深拷貝理解

Python中的可變,不可變物件;值型別,引用型別;淺拷貝,深拷貝理解

乍一看,好像有一些相通之處。

1. 可變物件和不可變物件

python中一切物件,型別也是物件
python中不可變型別有int,sring,tuple
可變型別有list和dict

看下面程式碼:

# 不可變物件
>>> a = 1
>>> id(a)
1752564208
>>> a = 2
>>> id(a)
1752564240

#可變物件
>>> la = [1,2,3]
>>> id(la)
2006131817800
>>> la[0] = 5
>>> 
id(la) 2006131817800 >>> la = [3,4,5] >>> id(la) 2006131818248

可以看到,int型別只要改變就是整個值得改變,而list型別的改變是內部元素的改變,當list整個全部改變的時候,它在記憶體中的地址也會發生變換,那麼string呢,在C語言中string不也是一串char嗎,看看

>>> str = "hello"
>>> id(str)
2006131950176
>>> str[0]
'h'
>>> str[0] = "w"
Traceback (most recent call last):
  File "<stdin>"
, line 1, in <module> TypeError: 'str' object does not support item assignment

也就是是說在python中string不能像list一樣理解,它是不可只改變內部元素值的,只要變就是全部變

總結: 可變物件和不可變物件的區別在於這個物件指向的這個地址是否允許它改變,允許則可變,不允許則不可變,如果要變,就要挪地方(改變地址)

2. 值型別和引用型別

前面已經說了可變型別與不可變型別了,值型別和引用型別與前面的概念十分相似。
看程式碼

# 值型別
>>> a = 1
>>> 
b =a >>> id(a) 1752564208 >>> id(b) 1752564208 >>> b = 2 >>> id(b) 1752564240 >>> id(a) 1752564208 #引用型別 >>> la = [1,2,3] >>> lb = la # lb是la的引用 >>> id(la) 1978265648264 >>> id(lb) 1978265648264 >>> lb[0] = 5 # 改變引用物件中單個元素 >>> lb [5, 2, 3] >>> la [5, 2, 3] >>> id(lb) 1978265648264 >>> id(la) 1978265648264 >>> lb = [2,3,4] # 改變引用物件中所有元素的值 >>> la [5, 2, 3] >>> lb [2, 3, 4] >>> id(la) 1978265648264 >>> id(lb) 1978265648904

想必已經很清晰了,可變物件和不可變物件,值型別和引用型別本質上是一樣一樣的東西,由於物件的可變與不可變才導致了物件是引用型別或者值型別
所以,值型別有int, string ,tuple等,
引用型別有list,dict等

3. 淺拷貝,深拷貝

知道了可變與不可變的intuition之後,淺拷貝和深拷貝就很簡單了,區別在於,前面兩種看的是他們的區別,而拷貝著重的他們的相同,看程式碼:

>>> la = [1,2,[3,4,5]]
>>> lb = la
>>> [id(x) for x in la]
[1752564208, 1752564240, 2065380752328]
>>> [id(x) for x in lb]
[1752564208, 1752564240, 2065380752328]
>>> lc = copy.copy(la)
>>> [id(x) for x in lc]
[1752564208, 1752564240, 2065380752328]
>>> ld = copy.deepcopy(la)
>>> [id(x) for x in ld]
[1752564208, 1752564240, 2065380752200]
>>> id(la)
2065380751880
>>> id(lb)
2065380751880
>>> id(lc)
2065380638792
>>> lc[2][0] = 0
>>> lc
[1, 2, [0, 4, 5]]
>>> la
[1, 2, [0, 4, 5]]
>>> ld[2][0] = 9
>>> ld
[1, 2, [9, 4, 5]]
>>> la
[1, 2, [0, 4, 5]]

其中lb,lc是淺拷貝,ld是深拷貝,淺拷貝是把物件內部的物件都看成可變型別來處理,而深拷貝是把物件內部的物件是否可變都分的很清楚。
注意: 淺拷貝時lc[2][0] = 0 雖然只是改變了第三個元素的第一個值但是不能寫lc[2] = [0,4,5],因為這樣寫的話,直譯器會認為你是全部改變了這個可變型別的值,從而重新給lc一個地址