淺拷貝
復(fù)制列表或者多數(shù)內(nèi)置的可變集合卵酪,最簡單的方式是使用內(nèi)置的類型構(gòu)造方法。比如表格里第二行谤碳,l2=list(l1)
溃卡,還能用l2=l1[:]
來創(chuàng)建副本。也能用模塊copy
來創(chuàng)建淺拷貝副本估蹄。
*關(guān)于[:]
塑煎,可以來看下LeetCode
第 283 題 Move Zeroes,很巧妙的用了[:]
解決問題臭蚁,運行時間超過了 99% 的submissions
最铁。
構(gòu)造方法list
或[:]
做的就是淺拷貝(淺復(fù)制)讯赏,也就是復(fù)制了最外層的容器,復(fù)制后的副本中的元素是原容器中元素的引用冷尉。
- 如果所有元素都是不可變的漱挎,那么沒有問題。但是如果有可變的元素雀哨,可能就會導(dǎo)致意想不到的問題磕谅。
行 | 輸入 |
---|---|
1 | l1 = [3, [55,44,66], (7,8,9)] |
2 | l2 = list(l1) |
3 | l1.append(100) |
4 | l1[1].remove(55) |
5 | print("l1:", l1) |
6 | print("l2:",l2) |
7 | l2[1] += [33,22] |
8 | l2[2] +=(10,11) |
9 | print("l1:", l1) |
10 | print("l2:",l2) |
output:
In [1]: l1: [3, [44, 66], (7, 8, 9), 100]
In [2]: l2: [3, [44, 66], (7, 8, 9)]
In [3]: l1: [3, [44, 66, 33, 22], (7, 8, 9), 100]
-
In [4]: l2: [3, [44, 66, 33, 22], (7, 8, 9, 10, 11)]
例如:
- 在第 3 行,我們向
l1
的容器里append
了100
雾棺,但是從打印的結(jié)果In [1]
和ln [2]
來看膊夹,l2
的容器并未發(fā)生變化。這里說的是對于元素100
來說捌浩;在輸入第 4 行放刨,我們對l1[1]
這個列表[55,44,66]
進(jìn)行了remove(55)
的操作,從輸出的結(jié)果來看尸饺,l1
和l2
的列表都發(fā)生了變化进统。這個就是淺拷貝的作用,即淺拷貝復(fù)制了外層容器浪听,但是內(nèi)部的對象引用是相同的螟碎。如果內(nèi)部的引用發(fā)生變化,那對應(yīng)淺拷貝得到的副本里的特定對象也將隨著改變迹栓。再比如我們在第 7 行掉分,也進(jìn)行了擴(kuò)大列表的操作,而對應(yīng)的ln[3]
和ln[4]
變化是相同的迈螟。 - 但對于不可變的元組來說叉抡,和列表就不一樣了尔崔。在第 8 行的輸入中答毫,我們向
l2[2]
的元組(7,8,9)
增加了(10,11)
元組,但從輸出ln [3]
和ln [4]
來看季春,ln [3]
的元組并未發(fā)生改變洗搂。這是為什么呢?這是因為元組在擴(kuò)大的時候载弄,直接創(chuàng)建了一個新的元組耘拇,和原來l1
里的元組(7,8,9)
完全無關(guān)。
- 在第 3 行,我們向
副本和原容器相等宇攻,但是二者指代不一樣的對象:
>>> l1 = [3, [55,44,66], (7,8,9)]
>>> l2 = list(l1)
>>> l2
[3, [55,44,66], (7,8,9)]
>>> l2 == l1
True
>>> l2 is l1
False
深拷貝
copy
模塊的copy
和deepcopy
分別用來創(chuàng)建淺拷貝和深拷貝副本:
如本文所述惫叛,淺拷貝得到的b
列表里的列表[1,2]
會受到原容器里的列表[1,2]
的remove(1)
操作的影響,因為a
和b
里的[1,2]
指向的是同一引用逞刷;而深拷貝得到的副本c
完全就是另一個對象了嘉涌,c
的原容器a
無論怎么發(fā)生變化妻熊,都和c
沒關(guān)系。