复制列表的最佳方式是什么?

68

最佳的列表复制方法是什么?我知道以下几种方法,哪一种更好?或者还有其他方式吗?

lst = ['one', 2, 3]

lst1 = list(lst)

lst2 = lst[:]

import copy
lst3 = copy.copy(lst)
7个回答

110
如果你想要一个浅拷贝(元素不会被复制),可以使用以下代码:
lst2=lst1[:]

如果想要进行深拷贝,请使用 copy 模块:

import copy
lst2=copy.deepcopy(lst1)

2
元素不被复制是什么意思? - sheats
6
如果元素是可变对象,它们将通过引用传递,您需要使用深度复制才能真正复制它们。 - Andrea Ambu
2
它只会复制列表所持有的引用。如果列表中的元素持有对另一个对象的引用,那么该引用不会被复制。十次中有九次你只需要浅拷贝。 - Jason Baker
3
更清晰的方法是:lst2 = list(lst1) - CᴴᴀZ
@CᴴᴀZ 所有提到的方法中,包括你提到的那个,哪一个是最好的,我指的是代码优化方面。 - Eswar
显示剩余3条评论

23

我经常使用:

lst2 = lst1 * 1

如果lst1包含其他容器(如其他列表),则应使用copy库中的深拷贝(deepcopy),如Mark所示。
更新:解释深拷贝。
>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55 
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])

正如您所看到的,只有一个更改后的列表是不足以进行比较的。因此,我们需要一些方式来将两个列表中的元素进行匹配和比较。

>>> 
>>> a = [range(i,i+3) for i in range(3)]
>>> a
[[0, 1, 2], [1, 2, 3], [2, 3, 4]]
>>> b = a*1
>>> a,b
([[0, 1, 2], [1, 2, 3], [2, 3, 4]], [[0, 1, 2], [1, 2, 3], [2, 3, 4]])

阅读起来不太方便,让我用for循环打印一下:

>>> for i in (a,b): print i   
[[0, 1, 2], [1, 2, 3], [2, 3, 4]]
[[0, 1, 2], [1, 2, 3], [2, 3, 4]]
>>> a[1].append('appended')
>>> for i in (a,b): print i

[[0, 1, 2], [1, 2, 3, 'appended'], [2, 3, 4]]
[[0, 1, 2], [1, 2, 3, 'appended'], [2, 3, 4]]

你看到了吗?它也被添加到了b[1]上,所以b[1]和a[1]是完全相同的对象。 现在试试用深度复制。

>>> from copy import deepcopy
>>> b = deepcopy(a)
>>> a[0].append('again...')
>>> for i in (a,b): print i

[[0, 1, 2, 'again...'], [1, 2, 3, 'appended'], [2, 3, 4]]
[[0, 1, 2], [1, 2, 3, 'appended'], [2, 3, 4]]

2
在最后一种情况下,copy() 无法工作,当对象内部有引用时,您需要使用 deepcopy() - Aram Kocharyan
1
我认为你使用 lst1*1 的技巧非常棒...但是,遗憾的是,粗略的分析表明它至少比 lst1[:] 慢两倍,而 copy(last1) 稍微快一点。 - Andrew

14

你还可以这样做:

a = [1, 2, 3]
b = list(a)

2
结果是浅拷贝还是深拷贝? - minty
9
不,使用list()肯定是浅拷贝。试一下就知道了。 - Christian Oudard
3
速度有差别吗?可以说,当你使用[:]时,库会聪明地知道正在进行复制操作,因此可能会调用一些本地的C代码来完成。而对于list(iterable),它是否知道或关心可迭代对象已经被实例化,因此可以高效地进行复制? - Hamish Grubijan
所以,获取列表深度拷贝的唯一方式是使用复制模块吗?看起来很奇怪,Python没有将深拷贝包含在标准功能中。 - Shuklaswag

7

我喜欢做的事情:

lst2 = list(lst1)

与 lst1[:] 相比的优点是,相同的习惯用法也适用于字典:
dct2 = dict(dct1)

实际上,在Python 3K邮件列表上就字典复制与列表复制进行了相当长时间的讨论:http://mail.python.org/pipermail/python-3000/2008-February/thread.html#12052 - Mark Roddy
这里的小提示是,对于字典,您可以执行d = d.copy()。 - Christian Oudard

3

短列表,使用[:]是最佳选择:

In [1]: l = range(10)

In [2]: %timeit list(l)
1000000 loops, best of 3: 477 ns per loop

In [3]: %timeit l[:]
1000000 loops, best of 3: 236 ns per loop

In [6]: %timeit copy(l)
1000000 loops, best of 3: 1.43 us per loop

对于更大的列表,它们都差不多:

In [7]: l = range(50000)

In [8]: %timeit list(l)
1000 loops, best of 3: 261 us per loop

In [9]: %timeit l[:]
1000 loops, best of 3: 261 us per loop

In [10]: %timeit copy(l)
1000 loops, best of 3: 248 us per loop

对于非常大的列表(我尝试了5000万),它们仍然差不多。

如果在100行代码之间只需要复制一次,我就不会费心。只有当它是应用程序的核心部分并且列表复制频繁时,我才会费心。 - Saurabh

2
你也可以这样做:
import copy
list2 = copy.copy(list1)

这应该与Mark Roddy的浅拷贝做同样的事情。

2

就性能而言,与切片相比,调用list()会有一些额外开销。因此对于短列表,lst2 = lst1[:]lst2 = list(lst1)快约两倍。

在大多数情况下,list()更易读,这可能超过了性能优化的价值,但在紧密循环中,这可能是一个有价值的优化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接