0.說明 python
先看看淺拷貝的概念:
編程
淺拷貝:對一個對象進行淺拷貝實際上是新建立了一個類型跟原對象同樣,其內容仍是原來對象元素的引用,換句話說,這個拷貝的對象自己是新的,可是它的內容不是ide
序列類型對象的淺拷貝是默認類型拷貝,有如下幾種實現方式:
函數
徹底切片操做:下面操做會有spa
利用工廠函數:好比list()、dict()等orm
使用copy模塊的copy()函數對象
其實若是是真正理解了Python對象或者說理解了可變對象和不可變對象,再根據上面的理論知識,淺拷貝和深拷貝基本上算是比較好的掌握了。因此這裏不按照書上(指的是《Python核心編程》)的思路來進行總結,固然書上的例子做爲入門也是很是不錯的。下面給出三個例子,若是均可以理解,那麼對Python淺拷貝和深拷貝的掌握到這個程度也就能夠了。it
1.第一個例子:列表中的元素都是原子類型,即不可變對象入門
>>> person = ['age', 20] >>> xpleaf = person[:] #淺拷貝 >>> cl = list(person) #淺拷貝 >>> [id(x) for x in person, xpleaf, cl] #雖然是淺拷貝,可是其實也是生成了新的對象 [140205544875144, 140205544893688, 140205544996232] >>> [id(x) for x in person] [140205545021232, 32419728] >>> [id(x) for x in xpleaf] [140205545021232, 32419728] >>> [id(x) for x in cl] [140205545021232, 32419728] #可是能夠看到列表中的元素的仍是原來對象元素的引用
上面作了淺拷貝的操做,而後下面修改兩個淺拷貝的值:class
>>> xpleaf[1] = 22 >>> cl[1] = 21 >>> person, xpleaf, cl (['age', 20], ['age', 22], ['age', 21]) >>> [id(x) for x in person] [140205545021232, 32419728] >>> [id(x) for x in xpleaf] [140205545021232, 32419680] >>> [id(x) for x in cl] [140205545021232, 32419704]
修改了兩個淺拷貝的值,而後發現內容並無相互影響,並且後來的id值也發生改變了,怎麼會這樣?不要忘了,列表中的元素都是不可變對象,修改不可變對象的值,其實就至關因而新生成了一個該對象,而後讓列表元素從新指向新生成的不可變對象,在這裏是數字對象。
理解這個例子自己並不難,但須要對Python對象和序列類型自己有必定的理解。
2. 第二個例子:列表中包含容器類型變量,便可變對象
>>> person = ['name', ['age', 20]] >>> xpleaf = person[:] >>> cl = list(person) >>> person, xpleaf, cl (['name', ['age', 20]], ['name', ['age', 20]], ['name', ['age', 20]]) >>> [id(x) for x in person, xpleaf, cl] [140205544995944, 140205544893688, 140205544875144] # 查看大列表的元素id值 >>> [id(x) for x in person, xpleaf, cl] [140205544996160, 140205544875144, 140205544996520] >>> [id(x) for x in person] [140205546176112, 140205544995944] >>> [id(x) for x in xpleaf] [140205546176112, 140205544995944] >>> [id(x) for x in cl] [140205546176112, 140205544995944] # 查看小列表的元素id值 >>> [id(x) for x in person[1]] [140205545021232, 32419680] >>> [id(x) for x in xpleaf[1]] [140205545021232, 32419680] >>> [id(x) for x in cl[1]] [140205545021232, 32419680]
三個列表的第一個元素的id值都是同樣的,這是引用傳遞,沒有什麼問題,跟第一個例子相似,所以修改這個值不會有什麼問題。但注意看第二個元素,它是一個列表,能夠確定的是,三個列表中的兩個元素的id也確定是相同的,也是引用傳遞的道理,但如今關鍵是看第二個元素,也就是這個列表自己,三個大列表(指的是person這個列表)中的這三個小列表的id值都是同樣的,因而,淺拷貝對於對象值的影響就會體現出來了,咱們嘗試去修改其中一個小列表中的值:
>>> xpleaf[1][1] = 22 >>> person, xpleaf, cl (['name', ['age', 22]], ['name', ['age', 22]], ['name', ['age', 22]]) >>> [id(x) for x in person, xpleaf, cl] [140205544995944, 140205544893688, 140205544875144] # 查看大列表的元素id值 >>> [id(x) for x in person] [140205546176112, 140205544995944] >>> [id(x) for x in xpleaf] [140205546176112, 140205544995944] >>> [id(x) for x in cl] [140205546176112, 140205544995944] # 查看小列表的元素id值 >>> [id(x) for x in person[1]] [140205545021232, 32419680] >>> [id(x) for x in xpleaf[1]] [140205545021232, 32419680] >>> [id(x) for x in cl[1]] [140205545021232, 32419680]
能夠看到問題就出來了,即對一個小列表進行修改,會影響到其它的小列表。咱們先拋開所謂的淺拷貝,去思考這個問題自己:有可能不會影響其它小列表嗎?確定沒有可能的,由於三個小列表的id都同樣,三個小列表裏的元素的id也同樣,即其實這三個小列表是徹底指向同一個對象的,所以,不管修改哪個,確定都會影響其它小列表的。
這就是所謂淺拷貝出現的問題。
3.第三個例子:使用深拷貝來解決第二個例子出現的問題
>>> person = ['name', ['age', 20]] >>> xpleaf = person[:] >>> from copy import deepcopy as dcp >>> cl = dcp(person) >>> person, xpleaf, cl (['name', ['age', 20]], ['name', ['age', 20]], ['name', ['age', 20]]) >>> [id(x) for x in person, xpleaf, cl] [140205544995944, 140205544893688, 140205544875144] # 查看大列表的元素id值 >>> [id(x) for x in person] [140205546176112, 140205544996520] >>> [id(x) for x in xpleaf] [140205546176112, 140205544996520] >>> [id(x) for x in cl] [140205546176112, 140205544571320] # 查看小列表的元素id值 >>> [id(x) for x in person[1]] [140205545021232, 32419728] >>> [id(x) for x in xpleaf[1]] [140205545021232, 32419728] >>> [id(x) for x in cl[1]] [140205545021232, 32419728]
能夠看到雖然是進行了深拷貝,但發現跟前面的其實並無什麼不一樣,下面咱們再來修改其中一個小列表:
>>> xpleaf[1][1] = 22 >>> person, xpleaf, cl (['name', ['age', 22]], ['name', ['age', 22]], ['name', ['age', 20]]) # 查看大列表的元素id值 >>> [id(x) for x in person] [140205546176112, 140205544996520] >>> [id(x) for x in xpleaf] [140205546176112, 140205544996520] >>> [id(x) for x in cl] [140205546176112, 140205544571320] # 查看小列表的元素id值 >>> [id(x) for x in person[1]] [140205545021232, 32419680] >>> [id(x) for x in xpleaf[1]] [140205545021232, 32419680] >>> [id(x) for x in cl[1]] [140205545021232, 32419728]
此時能夠看到,cl的小列表的第二個元素的id跟原來是同樣的,可是xpleaf和person的小列表元素的id發生了改變,同時值也是咱們修改的那樣。那是由於xpleaf是person的淺拷貝,可是cl是person的深拷貝。
這就是所謂的深拷貝。
4.第四個例子:檢驗
其實只要理解了上面三個例子(這意味着對Python對象自己和序列類型自己也有比較深入的理解),因此的淺拷貝和深拷貝也不是什麼問題了。
至因而否明白,能夠參考下面這個例子:
>>> person = ['name', ('hobby', [1, 2])] >>> xpleaf = person[:] >>> from copy import deepcopy as dcp >>> cl = dcp(person) >>> >>> xpleaf[0] = 'xpleaf' >>> cl[0] = 'cl' >>> person, xpleaf, cl (['name', ('hobby', [1, 2])], ['xpleaf', ('hobby', [1, 2])], ['cl', ('hobby', [1, 2])]) >>> >>> xpleaf[1][1][0] = 'clyyh' >>> person, xpleaf, cl (['name', ('hobby', ['clyyh', 2])], ['xpleaf', ('hobby', ['clyyh', 2])], ['cl', ('hobby', [1, 2])])
若是對這個例子的輸出以爲徹底沒有問題的,那麼也就OK了!
固然,確定還有遺漏的地方,還望指出。