lists-copies

列表复制

如下分别是三种复制, =,切片(Shallow Copy)和deepcopy

1
2
3
4
5
>>> from copy import deepcopy
>>> x = [[0, 1], [2, 3]]
>>> y = x
>>> z = x[:]
>>> u = deepcopy(x)

首先,这三种复制有共同点:

x==y==z==u返回True,它们的值都是一样的。

对于第一种=

因为列表是mutable对象,这里的y和x将指向同一个地址。

x is y返回True,表明它们是同一个object,只是两个names。

对于第二种和第三种,`z is x or u is x返回False

它们已经和原来的x不是同一个对象了,只是它们的values是相等的。

重点来了,

1
2
3
4
>>> x[0] = 4
>>> x[1][0] = 5
>>> x, y, z, u
([4, [5, 3]], [4, [5, 3]], [[0, 1], [5, 3]], [[0, 1], [2, 3]])

可以看见,当我们改变了x的第一个列表元素为整数4,第二个列表元素的第一个元素为5

yx保持一致,因为它们本身就是同一个object。

z是切片复制,浅复制。这个深浅是什么意思呢?x本身是个两层嵌套的列表。而浅复制z = x[:]就是指,建立一个和x等长的列表zz中每个元素按照顺序指向x中元素对应的地址。此时,x的第一个元素从指向一个列表为[0, 1]的地址变成指向整数4的地址。而x第二个元素的地址没有改变,改变的是x第二个元素中第一个元素的指向,从指向整数2变成指向整数5。我们可以使用验证它们第二个元素在内存中的地址是不是一样的。

1
2
>>> id(x[1]) == id(z[1])
True

而深复制u = deepcopy(x)就好理解了,创建一个新的对象,递归地对x中元素进行复制,并重新分配内存地址。所以ux已经是完全没有关联的对象。

待验证的个人说法,

y = x是把建立变量名称yx内存地址的映射。

z = x[:]是建立变量名称z到某列表的映射,该列表元素的内存地址与x元素的相等。

u = deepcopy(x)是建立变量名称u到某列表的映射,该列表元素的内存地址与x元素的无关。