python的淺拷貝和深拷貝

2021-10-07 14:06:02 字數 2626 閱讀 1218

1. python如何拷貝乙個物件?

在python中如何拷貝乙個物件呢?我們很多時候會用等號賦值法,除了=賦值,實際上還有淺拷貝和深拷貝,那麼賦值,淺拷貝和深拷貝到底有什麼區別呢?

(1) 賦值(=):建立了物件的乙個新的引用,修改其中任意乙個變數都會影響到另外乙個;

(2) 淺拷貝:建立乙個新的物件,但是它包含的是對原始物件中包含項的引用(如果用引用的方式修改其中乙個物件,另外乙個也會改變),即淺拷貝只拷貝頂層引用;

(3) 深拷貝:建立乙個新物件,並且遞迴的複製它所包含的物件(修改其中乙個,另外乙個不會改變),即深拷貝會逐層進行拷貝,直到拷貝的所有引用都是不可變引用為止。

淺拷貝和深拷貝從概念上看有點抽象,我們可以通過下面的例子來說明:

2. 舉例說明

例如有列表 l1=['aaa', 66, [1, 2, 3]],l2是對l1的賦值,l3是對l1的淺拷貝,l4是對l1的深拷貝。

>>> l1 = ['aaa', 66, [1, 2, 3]]

>>> l2 = l1

>>> l3 = l1.copy()

>>> l4 = copy.deepcopy(l1)

>>> id(l1)

140214926880712 ------> 指向同一塊記憶體位址

>>> id(l2)

140214926880712 ------> 賦值是拷貝引用,指向同一塊記憶體位址

>>> id(l3)

140215054238536 ------> 建立新的物件,即分配新的記憶體位址

>>> id(l4)

140214924504200

再列印列表l1的第3個元素的id:

>>> id(l1[2])

140214926939592

>>> id(l2[2])

140214926939592 ------> 賦值後第三個元素指向[1, 2, 3]的位址 可變物件

>>> id(l3[2])

140214926939592 ------> 淺拷貝後第三個元素指向[1, 2, 3]的位址 可變物件,這就是所謂的淺拷貝,只拷貝頂層引用

>>> id(l4[2])

140214926938440 ------> 深拷貝賦值所有的內容,所以第三個元素的記憶體位址與賦值和淺拷貝均不同,這就是所謂的深拷貝,遞迴賦值

修改l1的第3個元素,檢視賦值,淺拷貝,深拷貝的列表值的變化

>>> l1[2][0] = 4

>>> l1

['aaa', 66, [4, 2, 3]]

>>> l2

['aaa', 66, [4, 2, 3]] ------> 因為賦值l2是拷貝的l1的引用,l1的元素變化l2會跟著變化

>>> l3

['aaa', 66, [4, 2, 3]] ------> 因為淺拷貝l3的第三個元素拷貝的引用,故l3的第三個元素也會變化

>>> l4

['aaa', 66, [1, 2, 3]] ------> 可以看出深拷貝並不會因為l1的變化而影響,因為深拷貝會逐層進行拷貝,直到拷貝的所有引用都是不可變引用為止

接下來在列表l1追加乙個元素,觀察賦值,淺拷貝,深拷貝的列表值的變化:

>>> l1

['aaa', 66, [4, 2, 3], 88]

>>> l2

['aaa', 66, [4, 2, 3], 88] -------> 同理因為賦值l2是拷貝的l1的引用,l1的元素變化l2會跟著變化

>>> l3

['aaa', 66, [4, 2, 3]] -------> 到這裡應該就容易理解了吧,因為淺拷貝l3的記憶體是新分配的,故l1追加元素並不會影響淺拷貝l3的值

>>> l4

['aaa', 66, [1, 2, 3]] -------> 和我們預期的一樣,深拷貝依然不受影響

在這裡補充下例子中的淺拷貝,在python中一切皆是物件,通過概念我們可以看出淺拷貝是建立了乙個新的物件,但是這個新物件中的內容仍然是指向原始物件中包含項的引用,可以理解為淺拷貝是新物件,但是物件的包含項仍然是舊的引用。所以上面例子中,l1[2][0] =4 修改列表l1後淺拷貝的第3個元素會隨著l1的改變而變化,因為[1,2,3]本身就是個可變的列表,其在初始化時記憶體位址已經分配好,這個把記憶體位址拷貝給了l3;而 l1.aapend(88)執行後l3列表並沒有追加該元素,因為l3是個物件,是個新物件,與l1的記憶體位址不同,所以不會受影響。不知道我這裡有沒有講清楚。

3. 總結:

賦值:預設淺拷貝傳遞物件的引用而已,原始列表改變,被賦值的b也會做相同的改變;

淺拷貝:沒有拷貝子物件,所以原始資料改變,子物件會改變

深拷貝:包含物件裡面的子物件的拷貝,所以原始物件的改變不會造成深拷貝裡任何子元素的改變

在其他帖子看到對淺拷貝和深拷貝這樣的總結,挺有意思的:

淺拷貝就是藕斷絲連    ----只拷貝頂層引用,子項還存在引用關係

深拷貝就是離婚了 ----徹底沒關係了

為什麼python預設的拷貝方式是淺拷貝?

時間角度:淺拷貝花費時間更少;

空間角度:淺拷貝花費記憶體更少;

效率角度:淺拷貝只拷貝頂層資料,一般情況下比深拷貝效率高。

python 深拷貝 Python深拷貝和淺拷貝!

在python中,物件賦值實際上是物件的引用。當建立乙個物件,然後把它賦給另乙個變數的時候,python並沒有拷貝這個物件,而只是拷貝了這個物件的引用 一般有三種方法,alist 1,2,3,a b 1 直接賦值 b alist,預設淺拷貝傳遞物件的引用而已,原始列表改變,被賦值的b也會做相同的改變...

Python 深拷貝和淺拷貝

淺拷貝只拷貝了引用,並沒有拷貝內容,相當於把原來的引用複製了乙份給新的變數 深拷貝是將原來的值複製了乙份到新的地方 in 30 a 1,2,3 in 31 b a in 32 id a out 32 140618626865352 in 33 id b out 33 140618626865352 ...

python深拷貝和淺拷貝

copy.copy 淺拷貝 只拷貝父物件,不會拷貝物件的內部的子物件。比深拷貝更加節省記憶體 copy.deepcopy 深拷貝 拷貝物件及其子物件 用乙個簡單的例子說明如下 import copy公升 a 1,2,3,4,a b c b a c copy.copy a d copy.deepcop...