python 賦值 深拷貝 淺拷貝的區別

2021-10-09 07:36:43 字數 4411 閱讀 9364

昨天在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...