1. 程式人生 > >python可變型別vs不可變型別,深拷貝vs淺拷貝

python可變型別vs不可變型別,深拷貝vs淺拷貝

核心提示:

可變型別 Vs 不可變型別

可變型別(mutable):列表,字典

不可變型別(unmutable):數字,字串,元組

這裡的可變不可變,是指記憶體中的那塊內容(value)是否可以被改變

程式碼:

name1='wupeiqi'
name2=name1
print("name1:%s\nname2:%s" %(name1,name2))
name1='alex'
print("I have assigned new value to name1.Let's see what happens to name2!")
print("name1:%s\nname2:%s
" %(name1,name2))

執行結果:

C:/Personal/OldboyPython/day01/test.py
name1:wupeiqi
name2:wupeiqi
I have renamed name1 to new_name.Let's see what happens!
name1:alex
name2:wupeiqi

疑問:為什麼name2的值沒有和name1一起變為alex?下面開始解答,先看圖,後解釋。

以下引用自http://www.cnblogs.com/wupeiqi/articles/5433925.html

變數的賦值

#!/usr/bin/env python
# -*- coding: utf-8 -*-

name1 = "wupeiqi"
name2 = "alex"
#!/usr/bin/env python
# -*- coding: utf-8 -*-

name1 = "wupeiqi"   
name2 = name1     # 使name2和name1指向同一個物件 賦值,只是建立一個變數,該變數指向原來記憶體地址,
 以上引用自http://www.cnblogs.com/wupeiqi/articles/5433925.html

1.引用計數的增減

當物件wupeiqi(圖中藍色的記憶體區塊wupeiqi)被初次建立並(將其引用)賦值給變數name1時,物件wupeiqi的引用計數被設定為1。

當物件alex(圖中藍色的記憶體區塊alex)被初次建立並(將其引用)賦值給變數name2時,物件alex的引用計數被設定為1。

當變數name1賦值給變數name2(name2=name1),實際是把物件wupeiqi賦值給name2,因此物件wupeiqi的引用計數自動加1,而物件alex的引用計數自動減1,即減為0,觸發垃圾回收機制。

2. 可變型別 Vs 不可變型別

可變型別(mutable):列表,字典

不可變型別(unmutable):數字,字串,元組

這裡的可變不可變,是指記憶體中的那塊內容(value)是否可以被改變。如果是不可變型別,在對物件本身操作的時候,必須在記憶體中新申請一塊區域(因為老區域#不可變#)。如果是可變型別,對物件操作的時候,不需要再在其他地方申請記憶體,只需要在此物件後面連續申請(+/-)即可,也就是它的address會保持不變,但區域會變長或者變短。

可以使用內建函式id()來確認物件的身份在兩次賦值前後是否發生了變化。示例可參看http://blog.chinaunix.net/uid-26249349-id-3080279.html

*不可變型別有什麼好處?如果資料是不可變型別,當我們把資料傳給一個不瞭解的API時,可以確保我們的資料不會被修改。如果我們要操作一個從函式返回的元組,可以通過內建函式list()把它轉換成一個列表。(當被問到列表和元組的區別時,可以說這一點!)

3. 深拷貝 Vs 淺拷貝

copy.copy() 淺拷貝

copy.deepcopy() 深拷貝

淺拷貝是新建立了一個跟原物件一樣的型別,但是其內容是對原物件元素的引用。這個拷貝的物件本身是新的,但內容不是。拷貝序列型別物件(列表\元組)時,預設是淺拷貝。

 以下引用自http://www.cnblogs.com/wupeiqi/articles/5433925.html

賦值,只是建立一個變數,該變數指向原來記憶體地址,如下例:

n4 = n3 = n2 = n1 = "123/'Wu'"

關於賦值,再看一個字典的例子:

n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n2 = n1

 淺拷貝,在記憶體中只額外建立第一層資料,如下圖

import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n3 = copy.copy(n1)

深拷貝,在記憶體中將所有的資料重新建立一份(排除最後一層,即:python內部對字串和數字的優化,如下圖:

import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n4 = copy.deepcopy(n1)