python閒談----關於Python中列表的賦值與拷貝(淺拷貝、深拷貝)操作
阿新 • • 發佈:2018-12-14
- 列表作為python中最重要也是最基礎的序列,以其簡單方便的操作被廣泛應用,但在引用列表時也要注意一些小坑,這裡討論一下關於列表賦值的操作。
- 《Fluent Python》的作者Luciano Ramalho將序列按照記憶體模型分為容器序列和扁平序列
容器序列 | list、tuple、collections.deque |
---|---|
扁平序列 | str、bytes、bytearray、memoryview、array.array |
- 容器序列存放的是它們所包含的任意型別的物件的引用,而扁平序列裡存放的是值而不是引用。列表就是容器序列的一種,如一個列表可以是
[1,2,3,4]
,也可以是巢狀的[1,2,[3,4]]
列表的"="號賦值操作
案例:
a = [1,2,3,4]
b = a
a
>>> [1, 2, 3, 4]
b
>>> [1, 2, 3, 4]
a[0] = 5 # 將a列表的第一個資料修改為5
a
>>> [5, 2, 3, 4] # a列表發生變化
b
>>> [5, 2, 3, 4] # b列表也跟著改變
為什麼修改a列表的資料b列表也跟著變化?
事實上,a = [1,2,3,4]
表示將a指向一個列表的地址,而b = a
表示讓b也指向a所指向的地址:
a = [1,2,3,4]操作 b = a操作
因此修改a[0]實際上是在直接對地址中的值修改 由於b也指向列表的地址,因此b也會跟著改變
列表的淺拷貝
案例
import copy
a = [1,2,3,[4,5]]
b = a.copy() # 淺拷貝方法1
# b = copy.copy(a) # 淺拷貝方法2
# b = a[:] # 淺拷貝方法3
a
>>> [1, 2, 3, [4, 5]]
b
>>> [1, 2, 3, [4, 5]]
a[0] = 6 # 修改a列表的第一層資料
a
>>> [6, 2, 3, [4, 5]] # a列表的第一層資料發生改變
b
>>> [1, 2, 3, [4, 5]] # b列表不受影響
a[3][0] = 7 # 修改a列表的第二層資料
a
>>> [6, 2, 3, [7, 5]] # a列表的第二層資料發生改變
b
>>> [1, 2, 3, [7, 5]] # b列表的第二層資料也發生改變
上述案例中1,2,3都屬於第一層資料,而4,5因為在巢狀列表中屬於第二層資料(如果是多層巢狀,資料層數依次增加)。淺拷貝時會給新的拷貝物件開闢新的空間,但是隻會給第一層資料開闢空間,而第二層和更深層次的資料則採用引用的方式。如圖所示: 因為a[0]中的資料在第一層,當修改a[0]的資料時,僅僅是修改了a所指向的空間中的資料,b指向空間中的資料並未受影響
而當修改a[3][0]
中的資料時,由於a[3][0]
處於第二層資料,同時被a和b指向,當它發生改變時a和b的資料都會改變
- 因此淺拷貝可以理解為只拷貝第一層的資料,其他層資料只拷貝元素的引用