文/阿敏其人
本文出自“阿敏其人”簡書博客翘骂,轉載請取得本人同意。
首先帚豪,我們知道Python3中雏胃,有6個標準的數(shù)據(jù)類型,他們又分為可變和不可變志鞍。
不可變數(shù)據(jù)(3個):
- Number(數(shù)字)
- String(字符串)
- Tuple(元組)
可變數(shù)據(jù)(3個):
- List(列表)
- Dictionary(字典)
- Set(集合)
淺拷貝和深度拷貝 總結
淺拷貝
copy模塊里面的copy方法實現(xiàn)
1瞭亮、對于 不可 變類型 Number String Tuple,淺復制僅僅是地址指向,不會開辟新空間固棚。
2统翩、對于 可 變類型 List、Dictionary此洲、Set厂汗,淺復制會開辟新的空間地址(僅僅是最頂層開辟了新的空間,里層的元素地址還是一樣的)呜师,進行淺拷貝
-
3娶桦、淺拷貝后,改變原始對象中為可變類型的元素的值汁汗,會同時影響拷貝對象的衷畦;改變原始對象中為不可變類型的元素的值,只有原始類型受影響知牌。
(操作拷貝對象對原始對象的也是同理)
深拷貝
copy模塊里面的deepcopy方法實現(xiàn)
1祈争、淺拷貝,除了頂層拷貝角寸,還對子元素也進行了拷貝(本質上遞歸淺拷貝)
- 2菩混、
經(jīng)過深拷貝后,原始對象和拷貝對象所有的元素地址都沒有相同的了
淺拷貝
- 1扁藕、對于 不可 變類型 Number String Tuple,淺復制僅僅是地址指向沮峡,不會開辟新空間。
- 2亿柑、對于 可 變類型 List邢疙、Dictionary、Set,淺復制會開辟新的空間地址(僅僅是最頂層開辟了新的空間秘症,里層的元素地址還是一樣的)照卦,進行淺拷貝
- 3、淺拷貝后乡摹,改變原始對象中為可變類型的元素的值役耕,會同時影響拷貝對象的;改變原始對象中為不可變類型的元素的值聪廉,只有原始類型受影響瞬痘。 (操作拷貝對象對原始對象的也是同理)
可變類型和不可變類型在淺拷貝中的區(qū)別
import copy
# 不可變類型 Number String Tuple
print("對于不可 變類型 Number String Tuple,淺復制僅僅是地址指向,不會開辟新空間拷貝值")
num1 = 17
num2 = copy.copy(num1)
print("num1:" + str(id(num1)))
print("num2:" + str(id(num1)))
# num1和num2的地址都相同
str1 = "hello"
str2 = copy.copy(str1)
print("str1:" + str(id(str1)))
print("str2:" + str(id(str2)))
# str1和str2的地址都相同
tup1 = (18, "tom")
tup2 = copy.copy(tup1)
print("tup1:" + str(id(tup1)))
print("tup2:" + str(id(tup2)))
# tup1和tup2的地址都相同
print("="*20)
print("對于可變類型 List板熊、Dictionary框全、Set,淺復制會開辟新的空間地址(僅僅是最頂層開辟了新的空間)干签,進行淺拷貝")
list1 = [11,12]
list2 = copy.copy(list1)
print("list1:" + str(id(list1)))
print("list2:" + str(id(list2)))
# list1和list2的地址不相同
dic1 = [11,12,"hi"]
dic2 = copy.copy(dic1)
print("dic1:" + str(id(dic1)))
print("dic2:" + str(id(dic2)))
# dic1和dic2的地址不相同
set1 = {"AA","BB"}
set2 = copy.copy(set1)
print("set1:" + str(id(set1)))
print("set2:" + str(id(set2)))
# set1和set2的地址不相同
.
.
輸出:
對于不可 變類型 Number String Tuple,淺復制僅僅是地址指向津辩,不會開辟新空間拷貝值
num1:4449693616
num2:4449693616
str1:4452098488
str2:4452098488
tup1:4451942472
tup2:4451942472
====================
對于可變類型 List、Dictionary容劳、Set喘沿,淺復制會開辟新的空間地址,進行淺拷貝
list1:4456844424
list2:4452360136
dic1:4452358856
dic2:4456844744
set1:4452279016
set2:4452279464
對list進淺拷貝竭贩,對可變類型和不可變類型修改后的影響蚜印。
import copy
l1 = [11, 12]
l2 = [21, 22]
num = 555
allOne = [l1, l2,num]
# 淺拷貝,創(chuàng)建出一個對象留量,并把舊對象元素的 引用地址 拷貝到新對象當中窄赋。
# 也就是說,兩個對象里面的元素通過淺拷貝指向的還是同一個地址
allOne2 = copy.copy(allOne)
l1[0] = 16 # 此處修改楼熄,會使得 allOne 和 allOne2的第0個元素的值都發(fā)生改變忆绰,因為l1是List,是可變對象
allOne[2] = 666 # 此處修改孝赫,只會allOne的num的值较木,因為不可變對象一旦重新復制,地址就會發(fā)生改變青柄。(不可變嘛)
num = 777 # 此處不會改變 allOne 和 allOne2的值,因為相當于 777 復制給一個全新的地址预侯,這個num跟其他num已經(jīng)沒關系了
print(allOne)
print(allOne2)
print("id allOne:"+str(id(allOne)))
print("id allOne[0]:"+str(id(allOne[0])))
print("id allOne[1]:"+str(id(allOne[1])))
print("id allOne[2]:"+str(id(allOne[2])))
print("===")
print("id allOne2:"+str(id(allOne2)))
print("id allOne2[0]:"+str(id(allOne2[0])))
print("id allOne2[1]:"+str(id(allOne2[1])))
print("id allOne2[2]:"+str(id(allOne2[2])))
.
.
打印輸出
[[16, 12], [21, 22], 666]
[[16, 12], [21, 22], 555]
id allOne:4467341640
id allOne[0]:4471819912
id allOne[1]:4467342920
id allOne[2]:4466847696
===
id allOne2:4471820232
id allOne2[0]:4471819912
id allOne2[1]:4467342920
id allOne2[2]:4466081744
可以看出:
- 改動allOne中的可變類型致开,會影響allOne2,改變allOne2同理影響allOne萎馅。
- 改動allOne2中的不可變類型双戳,只有allOne2自身會改變,allOne不受影響糜芳。
(List是可變類型)
.
.
對于不可變類型被修改后造成的影響飒货,我們用一個更加簡單的例子便可更好理解:
num = 123
print(str(id(num)))
num = 666
print(str(id(num)))
.
.
console:
4348603632
4350009296
幾乎可以說魄衅,Python 沒有"變量",我們平時所說的變量其實只是"標簽"塘辅,是引用晃虫。
關于 = 符號,可以參考 python基礎(5):深入理解 python 中的賦值扣墩、引用哲银、拷貝、作用域
深拷貝
- 1呻惕、淺拷貝荆责,除了頂層拷貝,還對子元素也進行了拷貝(本質上遞歸淺拷貝)
- 2亚脆、經(jīng)過深拷貝后做院,原始對象和拷貝對象所有的子元素地址都是獨立的了
- 3、可以用分片表達式進行深拷貝
- 4濒持、字典的copy方法可以拷貝一個字典
深拷貝對6種基本類型的影響
我們對3種可變類型3種不可變類型進行深拷貝键耕。
結果發(fā)現(xiàn),和淺拷貝幾乎一致弥喉。
其實這也好理解郁竟,因為的深拷貝對比淺拷貝,強調的是 遞歸由境,強調的是資源素棚亩。
對了頂層的操作,深淺拷貝無異虏杰。
import copy
# 不可變類型 Number String Tuple
print("對于不可 變類型 Number String Tuple,深復制依然是地址指向讥蟆,不會開辟新空間拷貝值")
num1 = 17
num2 = copy.deepcopy(num1) # 深拷貝
print("num1:" + str(id(num1)))
print("num2:" + str(id(num1)))
# num1和num2的地址都相同
str1 = "hello"
str2 = copy.deepcopy(str1) # 深拷貝
print("str1:" + str(id(str1)))
print("str2:" + str(id(str2)))
# str1和str2的地址都相同
tup1 = (18, "tom")
tup2 = copy.deepcopy(tup1) # 深拷貝
print("tup1:" + str(id(tup1)))
print("tup2:" + str(id(tup2)))
# tup1和tup2的地址都相同
print("="*20)
print("對于可變類型 List、Dictionary纺阔、Set瘸彤,深拷貝會開辟新的空間地址,進行拷貝")
list1 = [11,12]
list2 = copy.deepcopy(list1) # 深拷貝
print("list1:" + str(id(list1)))
print("list2:" + str(id(list2)))
# list1和list2的地址不相同
dic1 = [11,12,"hi"]
dic2 = copy.deepcopy(dic1) # 深拷貝
print("dic1:" + str(id(dic1)))
print("dic2:" + str(id(dic2)))
# dic1和dic2的地址不相同
set1 = {"AA","BB"}
set2 = copy.deepcopy(set1) # 深拷貝
print("set1:" + str(id(set1)))
print("set2:" + str(id(set2)))
# set1和set2的地址不相同
深拷貝的會對子元素也進行拷貝
import copy
l1 = [11, 12]
l2 = [21, 22]
num = 555
allOne = [l1, l2,num]
# 淺拷貝笛钝,除了頂層拷貝质况,還對子元素也進行了拷貝(本質上遞歸淺拷貝)
# 經(jīng)過深拷貝后,原始對象和拷貝對象所有的元素地址都沒有相同的了
allOne2 = copy.deepcopy(allOne) # copy.deepcopy 深拷貝
allOne[1] = [113,114]
allOne2[2] = [227,228]
print(allOne)
print(allOne2)
print("id allOne:"+str(id(allOne)))
print("id allOne[0]:"+str(id(allOne[0])))
print("id allOne[1]:"+str(id(allOne[1])))
print("id allOne[2]:"+str(id(allOne[2])))
print("===")
print("id allOne2:"+str(id(allOne2)))
print("id allOne2[0]:"+str(id(allOne2[0])))
print("id allOne2[1]:"+str(id(allOne2[1])))
print("id allOne2[2]:"+str(id(allOne2[2])))
.
.
console
[[11, 12], [113, 114], 555]
[[11, 12], [21, 22], [227, 228]]
id allOne:4549589640
id allOne[0]:4554067720
id allOne[1]:4554067848
id allOne[2]:4548329424
===
id allOne2:4554067912
id allOne2[0]:4554067784
id allOne2[1]:4554067592
id allOne2[2]:4554100808
本例是跟淺拷貝做對比的玻靡。
在之前的淺拷貝中结榄,子元素是不會開辟新空間做拷貝的。
而在深拷貝中囤捻,子元素也進行了拷貝臼朗。
其他拷貝方式
除了copy模塊的中的copy和deepcopy,還有其他自帶的方式可實現(xiàn)拷貝。
- 1视哑、分片表達式進行淺拷貝
- 2绣否、字典的copy方法可以拷貝一個字典
分片表達式拷貝
l1 = [11, 12]
l2 = [21, 22]
num = 555
orgi = [l1, l2, num]
nList = orgi[:]
print("orgi:"+str(id(orgi)))
print("orgi[0]:"+str(id(orgi[0])))
print("orgi[1]:"+str(id(orgi[1])))
print("orgi[2]:"+str(id(orgi[2])))
print("*"*30)
print("nList:"+str(id(nList)))
print("nList[0]:"+str(id(nList[0])))
print("nList[1]:"+str(id(nList[1])))
print("nList[2]:"+str(id(nList[2])))
用分片表達式進行的拷貝,是淺拷貝挡毅。
字典自帶的copy方法可實現(xiàn)深拷貝
dic = {"key": "hello", "num": 18}
dic2 = dic.copy()
dic["key"] = "one"
dic2["key"] = "two"
print(dic)
print("dic:" + str(id(dic)))
print(dic2)
print("dic2:" + str(id(dic2)))
console:
{'key': 'one', 'num': 18}
dic:4382946792
{'key': 'two', 'num': 18}
dic2:4382946864
本文完蒜撮,謝謝閱讀。