首页 > 代码库 > Shallow Copy & Deep Copy in Python list

Shallow Copy & Deep Copy in Python list

  今天在写一个小程序的时候用到了2维数组, 顺手就写成了[[0.0]*length]*length, 结果为了这个小错,调试了半个多小时,

其实之前对与浅复制和深复制已经做过学习和总结, 但真正编程用到这些知识时还是掉入了陷阱中. 所以在此做进一步的总结:

  本文通过几个实例来说明Python中list的深复制和浅复制:

>>> a = [[]]*10>>> a[[], [], [], [], [], [], [], [], [], []]>>> a[0][0] = 10         #NO WayTraceback (most recent call last):  File "<stdin>", line 1, in <module>IndexError: list assignment index out of range>>> a[0].append(1)>>> a[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]>>> 

  a[0].append(1)后, 如果a的输出结果让你感到有些困惑,你可以参考这里(原因是Python中的*运算采用的是浅复制).

  同样的道理,下面的代码我们应该都能够理解:

>>> a[1].append(9)>>> a[[1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9]]>>> a[2][1] = 33>>> a[[1, 33], [1, 33], [1, 33], [1, 33], [1, 33], [1, 33], [1, 33], [1, 33], [1, 33], [1, 33]]>>> 

  让我们一起来分析一下:

  对于a(理解为一个2维数组)中的每一个元素都是一个list(理解为一个1维数组), 但我们需要注意的是a的每一个元素a[0],a[1],

a[2]...在内存中占用的是同一段内存区域(浅复制),所以更改(修改值或添加值)任何一个元素(a[0]或a[1]...a[9])都会直接影响到

其它的元素.

  如何验证a中的每一个元素a[0], a[1],...,a[9]在内存中占用相同的区域? 可以通过id方法来验证:

>>> id.__doc__"id(object) -> integer

Return the identity of an object. This is guaranteed to be unique among
simultaneously existing objects. (Hint: it‘s the object‘s memory address.)
"

 

>>> a = [[]]*10>>> a[[], [], [], [], [], [], [], [], [], []]>>> id(a[0])3071938316L>>> id(a[1])3071938316L>>> a[0].append(1)>>> a[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]>>> id(a[0])3071938316L>>> id(a[1])3071938316L>>> 

  那么应该怎么实现深复制呢?其实在前面提到的文章中已经介绍了这一方法:  

>>> c = [[] for i in range(10)]>>> c[[], [], [], [], [], [], [], [], [], []]>>> c[0].append(3)>>> c[[3], [], [], [], [], [], [], [], [], []]>>> 

  至此, 我觉得还有一点需要说明:

  一定要理解*操作的对象是谁, 例如: [2]*10得到[2, 2, 2, 2, 2, 2, 2, 2, 2, 2], *10操作的对象是[]中的2, 也就是说*10操

作使list中的元素2复制10次. 同理[[]]*10得到[[], [], [], [], [], [], [], [], [], []],*10操作的对象是[]中的[], 也就是说*10

操作使list中的元素[]浅复制10次, 这10个空list在内存中占有相同的区域(参见上面用id验证部分).

  下面用2段代码作为对比列出来, 便于查看:

>>> a = [2] * 10>>> a[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]>>> id(a[0])164067492>>> id(a[1])164067492>>> a[0] = 1  #NOTE>>> id(a[0])  #NOTE164067504>>> id(a[1])164067492>>> 

 

>>> b = [[]] * 10>>> b[[], [], [], [], [], [], [], [], [], []]>>> id(b[0])3072965964L>>> id(b[1])3072965964L>>> b[0].append(10)>>> id(b[0])3072965964L>>> id(b[1])3072965964L>>> b[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]>>> b[0][0] = 1>>> b[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]>>> id(b[0])3072965964L>>> id(b[1])3072965964L>>> b[0] = [10]>>> b[[10], [1], [1], [1], [1], [1], [1], [1], [1], [1]]>>> id(b[1])3072965964L>>> id(b[0])3072965996L>>> 

 

Shallow Copy & Deep Copy in Python list