felix已经提供了一个很好的答案,但我想我应该对各种方法进行速度比较: 10.59秒(105.9µs/itn)- copy.deepcopy(old_list) 10.16秒(101.6µs/itn)-纯python Copy() 方法使用deepcopy复制类 1.488秒(14.88µs/itn)-纯python Copy() 方法不复制类(仅DICT/列表/元组) 0.325秒(3.25µs/itn)- for item in old_list: new_list.append(item) 0.217秒(2.17µs/itn)- [i for i in old_list] (一份清单) 0.186秒(1.86µs/itn)- copy.copy(old_list) 0.075秒(0.75µs/itn)- list(old_list) 0.053秒(0.53µs/itn)- new_list = []; new_list.extend(old_list) 0.039秒(0.39µs/itn)- old_list[:] (列表切片) 所以最快的是列表切片。但是要知道 copy.copy() , list[:] 及 list(list) ,不像 copy.deepcopy() python版本不会复制列表中的任何列表、字典和类示例,因此如果原始列表发生更改,它们也会在复制的列表中发生更改,反之亦然。 (如果有人感兴趣或想提出任何问题,请看以下脚本:)
from copy import deepcopy
class old_class:
def __init__(self):
self.blah = 'blah'
class new_class(object):
def __init__(self):
self.blah = 'blah'
dignore = {str: None, unicode: None, int: None, type(None): None}
def Copy(obj, use_deepcopy=True):
t = type(obj)
if t in (list, tuple):
if t == tuple:
# Convert to a list if a tuple to
# allow assigning to when copying
is_tuple = True
obj = list(obj)
else:
# Otherwise just do a quick slice copy
obj = obj[:]
is_tuple = False
# Copy each item recursively
for x in xrange(len(obj)):
if type(obj[x]) in dignore:
continue
obj[x] = Copy(obj[x], use_deepcopy)
if is_tuple:
# Convert back into a tuple again
obj = tuple(obj)
elif t == dict:
# Use the fast shallow dict copy() method and copy any
# values which aren't immutable (like lists, dicts etc)
obj = obj.copy()
for k in obj:
if type(obj[k]) in dignore:
continue
obj[k] = Copy(obj[k], use_deepcopy)
elif t in dignore:
# Numeric or string/unicode?
# It's immutable, so ignore it!
pass
elif use_deepcopy:
obj = deepcopy(obj)
return obj
if __name__ == '__main__':
import copy
from time import time
num_times = 100000
L = [None, 'blah', 1, 543.4532,
['foo'], ('bar',), {'blah': 'blah'},
old_class(), new_class()]
t = time()
for i in xrange(num_times):
Copy(L)
print 'Custom Copy:', time()-t
t = time()
for i in xrange(num_times):
Copy(L, use_deepcopy=False)
print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t
t = time()
for i in xrange(num_times):
copy.copy(L)
print 'copy.copy:', time()-t
t = time()
for i in xrange(num_times):
copy.deepcopy(L)
print 'copy.deepcopy:', time()-t
t = time()
for i in xrange(num_times):
L[:]
print 'list slicing [:]:', time()-t
t = time()
for i in xrange(num_times):
list(L)
print 'list(L):', time()-t
t = time()
for i in xrange(num_times):
[i for i in L]
print 'list expression(L):', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(L)
print 'list extend:', time()-t
t = time()
for i in xrange(num_times):
a = []
for y in L:
a.append(y)
print 'list append:', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(i for i in L)
print 'generator expression extend:', time()-t
8条答案
按热度按时间zc0qhyus1#
felix已经提供了一个很好的答案,但我想我应该对各种方法进行速度比较:
10.59秒(105.9µs/itn)-
copy.deepcopy(old_list)
10.16秒(101.6µs/itn)-纯pythonCopy()
方法使用deepcopy复制类1.488秒(14.88µs/itn)-纯python
Copy()
方法不复制类(仅DICT/列表/元组)0.325秒(3.25µs/itn)-
for item in old_list: new_list.append(item)
0.217秒(2.17µs/itn)-[i for i in old_list]
(一份清单)0.186秒(1.86µs/itn)-
copy.copy(old_list)
0.075秒(0.75µs/itn)-list(old_list)
0.053秒(0.53µs/itn)-new_list = []; new_list.extend(old_list)
0.039秒(0.39µs/itn)-old_list[:]
(列表切片)所以最快的是列表切片。但是要知道
copy.copy()
,list[:]
及list(list)
,不像copy.deepcopy()
python版本不会复制列表中的任何列表、字典和类示例,因此如果原始列表发生更改,它们也会在复制的列表中发生更改,反之亦然。(如果有人感兴趣或想提出任何问题,请看以下脚本:)
cld4siwp2#
我听说Python3.3+添加了
list.copy()
方法,其速度应与切片速度相同:elcex8rz3#
在python中克隆或复制列表的选项有哪些?
在python 3中,可以通过以下方式创建浅拷贝:
在Python2和Python3中,您可以获得一个带有原始文件完整切片的浅拷贝:
解释
复制列表有两种语义方式。浅复制创建相同对象的新列表,深复制创建包含新等效对象的新列表。
浅表副本
浅表副本仅复制列表本身,列表本身是对列表中对象的引用的容器。如果包含的对象本身是可变的,并且其中一个对象发生了更改,那么更改将反映在两个列表中。
在Python2和Python3中有不同的方法来实现这一点。Python2的方法也适用于Python3。
python 2
在python 2中,制作列表的浅拷贝的惯用方法是使用原始列表的完整片段:
您也可以通过将列表传递给列表构造函数来完成相同的任务,
但使用构造函数的效率较低:
python 3
在Python3中,列表得到
list.copy
方法:在python 3.5中:
创建另一个指针不会创建副本
使用新列表=我的列表,然后在每次我的列表更改时修改新列表。为什么会这样?
my_list
只是指向内存中实际列表的名称。当你说new_list = my_list
你不是在复制,你只是在内存中添加另一个指向原始列表的名字。当我们复制列表时,可能会遇到类似的问题。列表只是指向内容的指针数组,因此浅层副本只是复制指针,因此有两个不同的列表,但它们具有相同的内容。要复制内容,您需要一份深度副本。
深拷贝
在Python2或Python3中,要制作列表的深度副本,请使用
deepcopy
在copy
模块:为了演示这如何允许我们创建新的子列表:
因此,我们看到深度复制的列表与原始列表完全不同。您可以使用自己的函数,但不要这样做。使用标准库的deepcopy函数很可能会产生错误,否则就不会产生错误。
不要使用eval
您可能会看到这被用作deepcopy的一种方式,但不要这样做:
这是危险的,尤其是当你从一个你不信任的来源评估某件事情时。
如果您要复制的子元素没有可以被评估以重现等效元素的表示,那么这是不可靠的。
它的性能也比较差。
在64位python 2.7中:
在64位python 3.5上:
wwwo4jvm4#
已经有很多答案告诉你如何制作一个合适的副本,但没有一个能说明你的原始“副本”失败的原因。
python不在变量中存储值;它将名称绑定到对象。您的原始任务获取了所引用的对象
my_list
把它绑在new_list
也无论您使用哪个名称,仍然只有一个列表,因此在将其称为my_list
将其称为new_list
. 这个问题的其他每个答案都为您提供了创建要绑定到的新对象的不同方法new_list
.列表中的每个元素都像一个名称,因为每个元素都非独占地绑定到一个对象。浅复制创建一个新列表,其元素与以前绑定到相同的对象。
要进一步复制列表,请复制列表引用的每个对象,并将这些元素副本绑定到新列表。
这还不是深度复制,因为列表的每个元素都可能引用其他对象,就像列表绑定到其元素一样。递归复制列表中的每个元素,然后复制每个元素引用的每个其他对象,依此类推:执行深度复制。
有关复制中的角案例的更多信息,请参阅文档。
acruukt95#
让我们从头开始,探讨这个问题。
那么让我们假设您有两个列表:
我们必须复制两个列表,现在从第一个列表开始:
首先,让我们尝试设置变量
copy
在我们原来的名单上,list_1
:现在,如果您认为复制复制了列表_1,那么您就错了。这个
id
函数可以显示两个变量是否可以指向同一个对象。让我们试试这个:输出为:
两个变量都是完全相同的参数。你感到惊讶吗?
所以我们知道,python不在变量中存储任何内容,变量只是引用对象,对象存储值。这里的对象是一个
list
但是我们用两个不同的变量名创建了对同一对象的两个引用。这意味着两个变量都指向同一个对象,只是名称不同。当你这样做的时候
copy = list_1
,它实际上在做:这里在图像列表_1和copy中有两个变量名,但两个变量的对象相同,即
list
.因此,如果您尝试修改复制的列表,那么它也会修改原始列表,因为该列表只有一个,您将修改该列表,无论您是从复制的列表还是从原始列表:
输出:
因此,它修改了原始列表:
现在让我们转到复制列表的pythonic方法。
此方法修复了我们遇到的第一个问题:
所以我们可以看到我们的两个列表都有不同的id,这意味着两个变量都指向不同的对象。所以这里实际发生的是:
现在,让我们尝试修改列表,看看我们是否仍然面临前面的问题:
输出为:
如您所见,它只修改了复制的列表。这意味着它成功了。
你认为我们结束了吗?不,让我们试着复制嵌套列表。
print(id((list_2)), id(copy_2))
4330403592 4330403528
copy_2[0][1] = "modify"
print(list_2, copy_2)
'01', 'modify''01', 'modify'
copy_2 = list_2[:]
print(id(copy_2[0]))
print(id(list_2[0]))
4329485832
4329485832
from copy import deepcopy
deep = deepcopy(list_2)
print(id((list_2)), id(deep))
4322146056 4322148040
print(id(deep[0]))
print(id(list_2[0]))
4322145992
4322145800
deep[0][1] = "modify"
print(list_2, deep)
'01', '98''01', 'modify'
wfveoks06#
使用
thing[:]
```zlhcx6iw7#
python 3.6计时
下面是使用python 3.6.8的计时结果。请记住,这些时间是相对的,而不是绝对的。
我坚持只做浅显的复印
rryofs0p8#
具有
new_list = my_list
,您实际上没有两个列表。赋值只是将引用复制到列表,而不是实际的列表,因此new_list
及my_list
作业结束后,请参阅相同的列表。要实际复制列表,您有多种可能:
你可以使用内置的
list.copy()
方法(从python 3.3开始提供):您可以将其切片:
alex martelli对此的看法(至少在2007年)是,这是一种奇怪的语法,使用它是没有意义的(在他看来,下一个更具可读性)。
您可以使用内置的
list()
功能:您可以使用泛型
copy.copy()
:这比以前慢了一点
list()
因为它必须找出old_list
第一。如果列表包含对象,并且您也希望复制它们,请使用“通用”
copy.deepcopy()
:显然,这是最慢、最需要记忆的方法,但有时是不可避免的。
例子:
结果: