列表对象的 copy() 方法返回列表的浅复制。
浅复制,是指生成一个新的列表,并且把原列表中所有元素的引用都都复制到新列表中。 如果原列表中只包含整数、实数、复数等基本类型或元组、字符串这样的不可变类型的数据,一般是没有问题的。但是,如果原列表中包含列表之类的可变数据类型,由于浅复制时只是把子列表的引用复制到新列表中,于是修改任何一个都会影响另一个。
x = [1, 2, [3, 4]] # 原列表中包含子列表
y = x.copy() # 浅复制
print(id(x), x)
print(id(y), y) # 两个列表中的内容完全一样
print(id(x[-1]), id(y[-1]))
y[2].append(5) # 为新列表中的子列表追加元素
y.append(9) # 在新列表的尾部追加元素
print((x, y))
x.append(8)
x[0] = 0 # 整数、实数等不可变类型不受此影响
print((x, y))
列表对象的 copy() 方法和切片操作以及标准库 copy 中的 copy() 函数都是返回浅复制。如果想避免上面代码演示的问题,可以使用标准库 copy 中的 deepcopy() 函数实现深复制。深复制,是指对原列表中的元素进行递归,把所有的值都复制到新列表中,对嵌套的子列表不再是复制引用。 这样,新列表和和原列表是相互独立的,修改任何一个不会影响另外一个。
import copy
x = [1, 2, [3, 4]] # 原列表中包含子列表
y = copy.deepcopy(x) # 深复制
print(id(x), x)
print(id(y), y) # 两个列表中的内容完全一样
print((id(x[-1]), id(y[-1])), (id(x[0]), id(y[0])))
y[2].append(5) # 为新列表中的子列表追加元素
y.append(9) # 在新列表的尾部追加元素
print((x, y))
x.append(8)
x[0] = 0
print((x, y))
无论是浅复制还是深复制,与列表对象的直接赋值都是不一样的。
① 下面的代码把同一个列表赋值给两个不同的变量,这两个变量是互相独立的,修改任何一个都不会影响另外一个。
x = [1, 2, [3, 4]]
y = [1, 2, [3, 4]]
print(id(x), id(y))
print((id(x[-1]), id(y[-1])), (id(x[0]), id(y[0])))
x.append(5)
x[2].append(6)
print(x, y)
② 下面的代码演示的是另外一种情况,把一个列表变量赋值给另外一个变量,这样两个变量指向同一个列表对象,对其中一个做的任何修改都会立刻在另外一个变量得到体现。
x = [1, 2, [3, 4]]
y = x
print(id(x), id(y))
print((id(x[-1]), id(y[-1])), (id(x[0]), id(y[0])))
x[2].append(5)
x.append(6)
x[0] = 7
print(x, y)