1. 程式人生 > >python閒談----關於Python中列表的賦值與拷貝(淺拷貝、深拷貝)操作

python閒談----關於Python中列表的賦值與拷貝(淺拷貝、深拷貝)操作

  • 列表作為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的資料都會改變 修改第二層資料

  • 因此淺拷貝可以理解為只拷貝第一層的資料,其他層資料只拷貝元素的引用

列表的深拷貝