Python學習筆記(5) 賦值 淺拷貝 深拷貝

2021-08-01 12:09:31 字數 4447 閱讀 8555

與很多程式語言一樣,python的拷貝方式分為賦值、淺拷貝、深拷貝。

在學習過程中,我對拷貝的了解很模糊。在經過一系列的實驗後,我對這三者的概念有了進一步的理解。

首先,我們要對賦值操作有以下認識:

我們通過一些例子來分析下賦值操作:

1.1 字串賦值

a = 'hello'

b = 'hello'

c = a

print(a, b, c)

# hello hello hello

[id(x) for x in [a,b,c]]

# [4526716328, 4526716328, 4526716328]

我們可以發現a, b, c三者的id是一樣的,以上操作相當於c = a = b = 『hello』,為什麼呢?因為str是不可變型別,所以』hello』只有乙個記憶體位址,a, b, c三者的id一樣。賦值是系統先給乙個變數或者物件(這裡是』hello』)分配了記憶體,然後再將id賦給a, b, c,所以它們的id是相同的。

a = 'world'

print(a, b, c)

# world hello hello

[id(x) for x in [a,b,c]]

# [4526651464, 4526716328, 4526716328]

這時a的id和值變了,但是b, c的id和值都未變。因為str是不可變型別,不同str占用不同的記憶體空間。重新賦值a需要新開闢記憶體空間,再把a指向新的str記憶體位址,所以當a的str值改變,a指向的記憶體位址也會改變。b, c由於字串』hello』的不變性,所以id和值都不會發生改變。

1.2 列表賦值

a = ['hello']

b = ['hello']

c = a

print(a, b, c)

# ['hello'] ['hello'] ['hello']

[id(x) for x in [a, b, c]]

# [4535290824, 4535290888, 4535290824]

為何a和b的id不同?因為list是可變型別,任意乙個list占用不同的記憶體位址。

print(a, b, c)

# ['hello', 12] ['hello'] ['hello', 12]

[id(x) for x in [a,b,c]]

# [4535290824, 4535290888, 4535290824]

a和c的值均改變,id沒有改變;變數b的id和值都沒有改變。由於list的可變性,所以修改list的值不需要另外開闢空間,只需修改原位址的值,所以a, c的值均改變,id沒有改變。

對於數字,字串和其他原子型別物件等,沒有被拷貝的說法。即便是用深拷貝,檢視id也是一樣的;如果對其重新賦值,也只是新建立乙個物件,替換掉舊的而已。

所謂淺拷貝就是對引用的拷貝。

2.1 利用切片操作和工廠方法(list方法)拷貝

**場景:有乙個小伙jack,tom通過切片操作拷貝jack,anny通過工廠方法拷貝jack。

jack = ['jack', ['age', 20]]

tom = jack[:]

anny = list(jack)

print(id(jack), id(tom), id(anny))

# 4570999880 4570944008 4570999752

從id來看,三者是不同的物件。

2.2 修改原物件的值

tom[0] = 'tom'

anny[0] = 'anny'

anny[1][1] = 18

print(jack, tom, anny)

# ['jack', ['age', 18]] ['tom', ['age', 18]] ['anny', ['age', 18]]

print(id(jack), id(tom), id(anny))

# 4570999880 4570944008 4570999752

奇怪的事情發生了,jack、tom、anny的年齡都變成18了。jack、tom、anny他們應當都是不同的物件,怎麼會互相影響呢?看下jack,tom,anny的內部元素每個元素id:

print([id(x) for x in jack])

# [4570490672, 4571499784]

print([id(x) for x in tom])

# [4570491232, 4571499784]

print([id(x) for x in anny])

# [4570490616, 4571499784]

恍然大悟,原來jack、tom、anny的年齡指向的是同乙個list元素,修改了其中乙個,當然影響其他人了。為了便於理解,我畫了乙個草圖:

利用切片操作和工廠方法(list方法)拷貝叫淺拷貝。它只是拷貝了最外圍的物件本身,內部的元素都只是拷貝了乙個引用而已。

利用copy中的deepcopy方法進行拷貝就叫做深拷貝,外圍和內部元素都進行了拷貝物件本身,而不是引用。它是完全拷貝了乙個副本,變數內部元素id都不一樣。

3.1 copy.deepcopy

我們利用copy模組中的deepcopy方法進行深拷貝。

import copy

jack = ['jack', ['age', '20']]

tom = copy.deepcopy(jack)

anny = copy.deepcopy(jack)

print([id(x) for x in [jack, tom, anny]])

# [4526691976, 4526690440, 4526692936]。因為list是可變型別,所以jack, tom, anny的id不同

print([id(x) for x in jack])

# [4526653368, 4526690568],'jack'是str不可變型別,['age','20']是list可變型別

print([id(x) for x in tom])

# [4526653368, 4526644488]

print([id(x) for x in anny])

# [4526653368, 4526642120]

深拷貝後,可以發現jack, tom,anny的id以及元素值均不相同。這才是完全拷貝了乙個副本 。

3.2 修改原資料

tom[0] = 'tom'

anny[0] = 'anny'

print(jack, tom, anny)

# ['jack', ['age', '20']] ['tom', ['age', '20']] ['anny', ['age',20]]

anny[1][1] =18

(24)

print(jack, tom, anny)

# ['jack', ['age', '20']] ['tom', ['age', '20'

,24]] ['anny', ['age',18]]

修改jack, tom,anny,它們之間不會互相影響。列印出每個人的內部元素id。

print([id(x) for x in [jack, tom, anny]])

# [4526691976, 4526690440, 4526692936]

print([id(x) for x in jack])

# [139132064, 3073507244l]

print([id(x) for x in tom])

# [139137464, 139132204]

print([id(x) for x in anny])

# [139141632, 139157548]

深拷貝後,jack,tom,anny元素id均不同,內部元素也都指向了不同的物件。這是完全拷貝的乙個副本,修改jack後,tom沒有發生改變,因為tom是乙個完全的副本,元素id與jack均不同,jack修改不影響tom。

賦值是把乙個物件記憶體位址賦給乙個變數,讓變數指向該記憶體位址( 舊瓶裝舊酒 )

淺拷貝是在另一塊位址中建立乙個新的變數或容器,但是容器內的元素的位址均是源物件的元素的位址的拷貝。也就是說新的容器中指向了舊的元素( 新瓶裝舊酒 )

深拷貝是在另一塊位址中建立乙個新的變數或容器,同時容器內的元素的位址也是新開闢的,僅僅是值相同而已,是完全的副本。也就是說( 新瓶裝新酒 )

python中的賦值、淺拷貝、深拷貝介紹

js 淺拷貝直接賦值 js的賦值與淺拷貝 深拷貝

昨天翻了下陣列api,看到concat和slice方法,突然想到這個兩個方法是淺拷貝還是深拷貝,結果陷入了死胡同,為什麼mdn文件說是淺拷貝,但進行簡單的操作為什麼能複製成功啊,糾結半天後才弄清原由,原來我一直把賦值和深淺拷貝搞混了。首先不要把引用型別的賦值歸結為淺拷貝,深拷貝和淺拷貝只針對像 ob...

python學習筆記番外 linux檔案拷貝程式

import os import shutil import sys def copydir orignaldir,destdir if not os.path.exists destdir os.mkdir destdir 獲取原目錄下的檔案和目錄,進行複製 orignaldirlist os.l...

python的深賦值與淺賦值

原文 在python中,物件賦值實際上是物件的的引用,當建立乙個物件,然後把它賦值給另外乙個變數的時候,python沒有拷貝這個物件,而只是拷貝了這個物件的引用,所以就出現了淺複製,即複製後原物件改變後,複製出來的物件也會改變,要防止複製出來的物件改變,就要使用深複製 python複製三種方式 1 ...