如何正确地拷贝python中的列表

在stackoverflow闲逛,发现了这个问题。答案中很多亮点,比如这个。其中提到如何区分一个pythoner到底是不是个新手,然后给出了这道题:



还指出,能够准确说出答案不重要,重要的是说出为什么。的确,两个一对比,很容易猜的出来:Ex1中x是43,y是42,Ex2中x是[4,2,3],y也是。

要知道为什么首先要明确python中变量的概念:c语言中的变量对应着某些字节,而python中变量不过是某个对象的一个标签而已。
[cc lang=”python”]
>>> x = 42
>>> y = x
>>> id(x)
145468284
>>> id(y)
145468284
[/cc]
通过id函数可以看到,x和y对应的其实是同一个对象。

再回到原来的问题。Ex1中使用的是一个数字,而Ex2则是用的一个列表。它们最大的区别就是数字是不可变类型而列表是可变的。当尝试修改一个不可变类型的变量时,会发生什么呢?
[cc lang=”python”]
>>> x = 42
>>> y = x
>>> id(x)
145468284
>>> id(y)
145468284
>>> x = x + 1
>>> id(x)
145468272
>>> id(y)
145468284
[/cc]
当尝试改变x的值时,又产生了一个新的对象。x变量也就成了指向这个新对象的标签。y变量依然保持不变。下面再来看修改列表的情况:
[cc lang=”python”]
>>> x = [1, 2, 3]
>>> y = x
>>> id(x)
3078448364L
>>> id(y)
3078448364L
>>> x[0] = 4
>>> id(x)
3078448364L
>>> id(y)
3078448364L
>>> print x
[4, 2, 3]
>>> print y
[4, 2, 3]
[/cc]
因为列表本身是可变的,所以修改x时并不会产生新的对象。因此会出现上面的结果。

既然通过赋值的方法仅仅是增加了一个对同一对象的引用,那有什么方法可以达到拷贝的目的呢?切片是一个很好的选择。
[cc lang=”python”]
>>> x= [1,2,3]
>>> id(x)
20028992
>>> y = x[:]
>>> id(y)
20054064
[/cc]
使用list工厂函数也可以拷贝列表:
[cc lang=”python”]
>>> x = [1, 2, 3]
>>> id(x)
20013704
>>> y = list(x)
>>> id(y)
20029392
[/cc]
另外,还可以使用copy模块中的copy函数。

但是,上述的三种方法,都是属于“浅拷贝”。“浅拷贝”与“深拷贝”的区别在将下一篇文章中介绍。

发表评论

电子邮件地址不会被公开。 必填项已用*标注