一、可變對象與非可變對象
想要理解淺拷貝與深拷貝就必須得先明白可變對象與非可變對象。
可變對象有: list ,dict ,set
??????? 不可變對象有:int ,float ,bool ,str ,tuple 。
兩者區別:對于可變對象,其值改變是在原地址上操作,不會創建新的內存地址。對于不可變對象其值改變是直接創建新的內存地址。
二、賦值操作符‘=’表示對象的引用。
python里面的?賦值操作符‘=’實際上是對象的引用,其并沒有進行復制操作。如果如果賦值操作符右邊的操作數是字面值,比如字符串或者數字,那么左邊的操作數被設為一個對象的引用,該對象將指向存放字面值得內存對象。(a=1,a指向1的內存對象)。如果右邊的操作數是一個對象引用,那么左邊的操作數將設置為一個對象引用,并與右邊的操作數是一個對象引用,并與右邊的操作數指向相同的對象。(b=a,則a,b均指向1的內存對象)
>>> a=1 #a引用對象1(指向1的地址)
>>> b=a # b引用對象a實際上也是引用對象1 ?。ǎ庵赶颍钡牡刂罚?>>> id(a)
94474006287136
>>> id(b)
94474006287136
>>> a=2 #a引用對象2,由于對象2相對對象1發生了改變,則重新創建新的內存里面 存的是對象2?。ǎ嶂赶颍蔡幍牡刂罚?>>> id(a)
94474006287168
>>> id(b) # b繼續引用之前的對象1 (b還是指向之前1的地址不變)
94474006287136
>>>
>>> a=[1,2,3,4]
>>> b=a
>>> b
[1, 2, 3, 4]
>>> a.append(5)
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3, 4, 5]
由上可以發現列表a賦值給b時,實際上a和b都指向同一內存地址。由于列表a是可變對象,對a進行append操作后是在原地址上操作,所以b也跟著改變了。
二、
淺拷貝 copy.copy()
1.對于不可變類型 Number String Tuple,淺復制僅僅是地址指向,不會開辟新空間。
>>> a='hello world'
>>> b=a
>>> id(a)
140620341876400
>>> id(b)
140620341876400
>>> c=copy.copy(a)
>>> c
'hello world'
>>> id(c)
140620341876400
>>>
對于下面的情況:將a的地址指向改變下,但是b和c的地址仍然不變,指向原來的地址。
>>> a=5 # 將a的地址指向由‘hello world'改為指向5
>>> id(a)
94474006287264
>>> id(b)
140620341876400
>>> id(c)
140620341876400
>>>
?。玻畬τ诳勺冾愋?List、Dictionary、Set,淺復制會開辟新的內存存放其指向的地址(僅僅是最頂層開辟了新的內存,里層的元素地址還是一樣的)
>>> a=[1,2,3,[4,5,6],7,8] #列表中子對象(子列表[4,5,6])
>>> b=a
>>> c=copy.copy(a)
>>> id(a)
140620341875976
>>> id(b)
140620341875976
>>> id(c) # 淺copy 外層開辟新的內存,c的內存地址與a不一樣
140620341876104
>>> id(a[3]) # 里層的內存地址
140620341814920
>>> id(d[3])
140620341875720
>>> id(c[3]) # 淺拷貝后的里層的內存地址與原對象的里層內存地址一樣。里層在淺copy時 作為公共部分使用,淺拷貝時這部分不會重新創建新的內存
140620341814920
?。? 可變類型 (只有可變類型才能對應后面的改變)淺拷貝后, 改變 原始對象中為可變類型的元素的值,會同時影響拷貝對象的;改變原始對象中為不可變類型的元素的值,只有原始類型受影響。
>>> a=[1,2,3,{'a':'A'}]
>>> c=copy.copy(a)
>>> id(a)
140620341875976
>>> id(c)
140620341680264
>>> a[0]=0
>>> a
[0, 2, 3, {'a': 'A'}]
>>> c
[1, 2, 3, {'a': 'A'}]
>>> id(a[0])
94474006287104
>>> id(c[0])
94474006287136
>>> a[3]['a']='AAA'
>>> a
[0, 2, 3, {'a': 'AAA'}]
>>> c
[1, 2, 3, {'a': 'AAA'}]
>>> id(a[3])
140620366602104
>>> id(c[3])
140620366602104
>>>
總結:淺拷貝(復制) 只是拷貝了對象引用,而非對象本身。 對于不可變數據,淺拷貝就當于我們所理解的復制,此時也等價于深拷貝。對于可變數據類型,其元素是不可變時與上述一樣,如果是可變元素時, 比如列表中有嵌套列表,嵌套列表的引用也被復制,當嵌套列表改變時,其內存地址不變即淺拷貝后其嵌套列表也是跟著變得。
三、深拷貝copy.deepcopy()
??????? 深拷貝就是通常我們所理解的,完全的拷貝并重新創建新的內存空間(包括外層和里層)。
>>> a=[1,2,3,[4,5,6]]
>>> b=copy.deepcopy(a)
>>> id(a)
140620341875976
>>> id(b)
140620341876104
>>> a[3][0]=0
>>> a
[1, 2, 3, [0, 5, 6]]
>>> b
[1, 2, 3, [4, 5, 6]]
四、其他等價的淺拷貝。
? ? ? ?除了淺拷貝copy.copy外,對于列表還是其他的操作等價于淺拷貝。比如切片和類型名作為函數。
使用類型名作為函數的還有如下
copy_of_dict=dict(d)
copt_of_set=set(s)
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
