昨天在leetcode上遇見一道有關回溯演算法的題目遇見了這個問題:
問題:然後對cur使用pop操作。
結果儲存在res的cur也被修改了。
而如果使用圖中的切片操作則可以避免這個問題。
這就涉及到了深拷貝,淺拷貝。
在講深拷貝之前,先看一下python的賦值操作, 也就是等於:
a =[1
,2,3
,4]b = a
print(,
id(a)
)print(,
id(b)
)
列印結果:
可以看見,進行賦值操作的時候,變數a和變數b都指向了同乙個位址,也就是說,只是並沒有建立乙個新的 list 容器,a和b本質上是乙個容器,它們裝著同樣的物質。這樣,如果將a中的物質給換掉,那麼b中的物質肯定做了相同的變化,因為它們本質上就是叫法不同的同乙個容器而已。
# 改變a裝的東西a[0
]="我變了"
print
("我是a:"
, a)
print
("我是b:"
, b)
所以它們做相同的變化:
我是a: [
'我變了',2
,3,4
]我是b: [
'我變了',2
,3,4
]
在開頭提到的列表切片操作就是淺拷貝,所以什麼是淺拷貝?
直觀的將,如果b是a淺拷貝而來,那麼a和b就不再是同乙個容器了,而是兩個不同的容器。
上**:
a =[1
,2,3
,4]b = a[:]
#淺拷貝
# 改變a裝的東西a[0
]="我變了"
print
("我是a:"
, a)
print
("我是b:"
, b)
結果:
我是a: [
'我變了',2
,3,4
]我是b: [1,
2,3,
4]
這個時候,改變a的元素0, a的元素0發生了改變,但是b的元素0沒有發生改變。那麼問題來了,a容器和b容器裝的東西是不是一樣的?
我們看:
a =[1
,2,3
,4]b = a[:]
#淺拷貝
print(,
[id(i)for i in a]
)print(,
[id(i)for i in b]
)
我是a的元素位址:
[140725704499600
,140725704499632
,140725704499664
,140725704499696
]我是b的元素位址:
[140725704499600
,140725704499632
,140725704499664
,140725704499696
]
容器裝的物質完全一樣,那為什麼改變a的元素0,b的元素不會改變呢?
答案就是:因為它們是兩個不同的容器(物件)!
一開始,它們裝的元素是一樣的,也就是它們指向了相同的東西。但是,你換了a的元素,那a容器的元素0就指向了其他的東西,而b容器和a容器壓根是兩個容器,因此b的元素指向的位址不會發生改變。
可以看見,容器a和容器b的元素0的指向是不一樣的, 而其他元素的指向是一樣的。
我是a的元素位址:
[2195726848528
,140726275449264
,140726275449296
,140726275449328
]我是b的元素位址:
[140726275449232
,140726275449264
,140726275449296
,140726275449328
]
但是淺拷貝有乙個問題,讓a中發生發生某種改變的時候,b也發生了某種改變:
這種情況就是容器裡面包含容器(可變型別):
a =[1
,2,3
,[-1
,-2,
-3]]
#元素3換成另外乙個list(可變型別)
b = a[:]
#淺拷貝
print(,
[id(i)for i in a]
)print(,
[id(i)for i in b])a[
3][0
]='我是容器a裡面容器的元素, 我變了'
print
("我是a:"
, a)
print
("我是b:"
, b)
print(,
[id(i)for i in a]
)print(,
[id(i)for i in b]
)
我是a的元素位址:
[140726275449232
,140726275449264
,140726275449296
,2156915020168
]我是b的元素位址:
[140726275449232
,140726275449264
,140726275449296
,2156915020168
]
然後看a變了之後,b變了沒有:
我是a: [1,
2,3,
['我是容器a裡面容器的元素, 我變了',-
2,-3
]]我是b: [1,
2,3,
['我是容器a裡面容器的元素, 我變了',-
2,-3
]]
b 也跟著發生變化,解釋就是a中元素3是乙個容器, b中元素3也是乙個容器,這兩個容器就是乙個相同的容器。還記得上面的賦值操作嗎?同乙個容器,對元素進行替換,容器裡面的元素肯定發生一樣的變化!這種現象對應的就是賦值。
所以,為了避免這種現象,就有了深拷貝。
先上**:
import copy
a =[1,
2,3,
[-1,
-2,-
3]]b = copy.deepcopy(a)
#深拷貝
這時候,容器a和容器b和淺拷貝一樣,不是同乙個容器:
print(id
(a))
print(id
(b))
2417826338760
2417826338504
再看看裡面裝的東西:
print(,
[id(i)for i in a]
)print(,
[id(i)for i in b]
)
我是a的元素位址:
[140725724815760
,140725724815792
,140725724815824
,2417826118280
]我是b的元素位址:
[140725724815760
,140725724815792
,140725724815824
,2417826107208
]
注意到,元素中的不可變型別和淺拷貝一樣,指向同樣的位址,但是可變元素,則換成了不同的容器(元素3的位址不一樣了),這不就是對容器裡面的可變元素(容器)進行了淺拷貝嗎?因此,現在改變a容器的元素3的乙個元素,則b不再進行相應變化:
a[3]
[0]=
'我是容器a裡面容器的元素, 我變了'
print
("我是a:"
, a)
print
("我是b:"
, b)
我是a: [1,
2,3,
['我是容器a裡面容器的元素, 我變了',-
2,-3
]]我是b: [1,
2,3,
[-1,
-2,-3]]
總結:賦值、淺拷貝、深拷貝一層套一層,有種盜夢空間的感覺。 Python 賦值 淺拷貝 深拷貝
賦值 a b,只拷貝了物件的引用,沒有拷貝內容。兩個物件的id一樣 淺拷貝 copy.copy 構造乙個新的復合物件,然後將子物件引用插入到原始物件的副本中。深拷貝 copy.deepcopy 構造乙個新的復合物件,然後遞迴地將子物件副本插入原始物件的副本。給個栗子 從這個栗子可以看出,對c進行修改...
python賦值 淺拷貝 深拷貝
視覺化 首先了解知識點 可變 list,dict 和不可變 string,int,tuple 淺拷貝 對於string int來說沒有意義,因為它們資料就一層,對於tuple由於是不可變型別所以新的物件會指向原來的物件位址,對於list和dict,新的物件會在記憶體中開闢乙個新的記憶體空間,並且只拷...
淺拷貝 深拷貝和淺賦值 深賦值
include includeusing namespace std class string else 淺拷貝 也就是系統預設的拷貝,可寫可不寫。string const string s 預設的拷貝構造 深拷貝 string const string s string s2 s1 深賦值 str...