如何克隆或复制列表?

时间:2010-04-10 08:49:47

标签: python list copy clone

在Python中克隆或复制列表有哪些选项?

使用new_list = my_list时,new_list的任何修改都会每次更改my_list。 这是为什么?

24 个答案:

答案 0 :(得分:2817)

使用new_list = my_list,您实际上没有两个列表。赋值只是复制对列表的引用,而不是实际列表,因此new_listmy_list在分配后引用相同的列表。

要实际复制列表,您有各种可能性:

  • 您可以使用内置list.copy()方法(自Python 3.3起可用):

    new_list = old_list.copy()
    
  • 您可以对其进行切片:

    new_list = old_list[:]
    

    Alex Martelli's关于这一点的意见(至少back in 2007),这是一种奇怪的语法,而且使用它是没有意义的。 ;)(在他看来,下一个更具可读性。)

  • 您可以使用内置的list()功能:

    new_list = list(old_list)
    
  • 您可以使用通用copy.copy()

    import copy
    new_list = copy.copy(old_list)
    

    这比list()慢一点,因为它必须首先找出old_list的数据类型。

  • 如果列表包含对象,并且您也想要复制它们,请使用泛型copy.deepcopy()

    import copy
    new_list = copy.deepcopy(old_list)
    

    显然是最慢和最需要记忆的方法,但有时是不可避免的。

示例:

import copy

class Foo(object):
    def __init__(self, val):
         self.val = val

    def __repr__(self):
        return str(self.val)

foo = Foo(1)

a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)

# edit orignal list and instance 
a.append('baz')
foo.val = 5

print('original: %r\n list.copy(): %r\n slice: %r\n list(): %r\n copy: %r\n deepcopy: %r'
      % (a, b, c, d, e, f))

结果:

original: ['foo', 5, 'baz']
list.copy(): ['foo', 5]
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]

答案 1 :(得分:528)

菲利克斯已经提供了一个很好的答案,但我想我会对各种方法进行速度比较:

  1. 10.59秒(105.9us / itn) - copy.deepcopy(old_list)
  2. 10.16秒(101.6us / itn) - 使用深度复制复制类的纯python Copy()方法
  3. 1.488秒(14.88us / itn) - 纯python Copy()方法不复制类(只有dicts / lists / tuples)
  4. 0.325秒(3.25us / itn) - for item in old_list: new_list.append(item)
  5. 0.217秒(2.17us / itn) - [i for i in old_list](a list comprehension
  6. 0.186秒(1.86us / itn) - copy.copy(old_list)
  7. 0.075秒(0.75us / itn) - list(old_list)
  8. 0.053秒(0.53us / itn) - new_list = []; new_list.extend(old_list)
  9. 0.039秒(0.39us / itn) - old_list[:]list slicing
  10. 所以最快的是列表切片。但要注意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
    

答案 2 :(得分:132)

我已经been told使用Python 3.3 + adds list.copy()方法,它应该像切片一样快:

newlist = old_list.copy()

答案 3 :(得分:113)

  

在Python中克隆或复制列表有哪些选项?

在Python 3中,可以使用:

创建浅表副本
a_copy = a_list.copy()

在Python 2和3中,你可以获得一个带有原始片段的浅拷贝:

a_copy = a_list[:]

说明

复制列表有两种语义方法。浅拷贝创建相同对象的新列表,深拷贝创建包含新等效对象的新列表。

浅名单副本

浅表副本仅复制列表本身,该列表是对列表中对象的引用的容器。如果包含的对象本身是可变的并且其中一个被更改,则更改将反映在两个列表中。

在Python 2和3中有不同的方法可以做到这一点.Python 2方法也适用于Python 3。

Python 2

在Python 2中,制作列表的浅表副本的惯用方法是使用原始的完整片段:

a_copy = a_list[:]

您也可以通过列表构造函数

传递列表来完成同样的事情
a_copy = list(a_list)

但使用构造函数的效率较低:

>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844

Python 3

在Python 3中,列表获取list.copy方法:

a_copy = a_list.copy()

在Python 3.5中:

>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125

制作另一个指针制作副本

  

使用new_list = my_list,每次my_list更改时修改new_list。这是为什么?

my_list只是一个指向内存中实际列表的名称。当您说new_list = my_list您没有复制时,您只是添加另一个指向内存中原始列表的名称。当我们制作列表副本时,我们可能会遇到类似的问题。

>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]

列表只是指向内容的指针数组,因此浅复制只复制指针,因此您有两个不同的列表,但它们具有相同的内容。要制作内容的副本,您需要一份深层副本。

深层拷贝

制作deep copy of a list, in Python 2 or 3, use deepcopy in the copy module

import copy
a_deep_copy = copy.deepcopy(a_list)

演示如何让我们创建新的子列表:

>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]

因此我们看到深层复制列表与原始列表完全不同。你可以自己动手 - 但不要。您可能会通过使用标准库的深度复制功能来创建您无法拥有的错误。

不要使用eval

您可能会将此视为深度镜检查的一种方式,但不要这样做:

problematic_deep_copy = eval(repr(a_list))
  1. 这很危险,特别是如果你从一个你不信任的来源评估某些东西。
  2. 如果您要复制的子元素没有可以重现等效元素的表示,那么它不可靠。
  3. 它的表现也不太好。
  4. 在64位Python 2.7中:

    >>> import timeit
    >>> import copy
    >>> l = range(10)
    >>> min(timeit.repeat(lambda: copy.deepcopy(l)))
    27.55826997756958
    >>> min(timeit.repeat(lambda: eval(repr(l))))
    29.04534101486206
    

    在64位Python 3.5上:

    >>> import timeit
    >>> import copy
    >>> l = list(range(10))
    >>> min(timeit.repeat(lambda: copy.deepcopy(l)))
    16.84255409205798
    >>> min(timeit.repeat(lambda: eval(repr(l))))
    34.813894678023644
    

答案 4 :(得分:49)

已经有很多答案可以告诉你如何制作一份正确的副本,但是没有一个人说你为什么原来的'副本'失败了。

Python不会将值存储在变量中;它将名称绑定到对象。您的原始作业采用了my_list引用的对象,并将其绑定到new_list。无论您使用哪个名称,仍然只有一个列表,因此在将其称为my_list时所做的更改将在将其称为new_list时保留。此问题的其他每个答案都为您提供了创建绑定到new_list的新对象的不同方法。

列表的每个元素都像一个名称,因为每个元素都非唯一地绑定到一个对象。浅拷贝创建一个新列表,其元素绑定到与以前相同的对象。

new_list = list(my_list)  # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]

要使列表副本更进一步,请复制列表引用的每个对象,并将这些元素副本绑定到新列表。

import copy  
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]

这还不是一个深层副本,因为列表的每个元素都可以引用其他对象,就像列表绑定到它的元素一样。以递归方式复制列表中的每个元素,然后复制每个元素引用的每个其他对象,依此类推:执行深层复制。

import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)

有关复制中的边角情况的详细信息,请参阅the documentation

答案 5 :(得分:31)

使用thing[:]

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 

答案 6 :(得分:30)

Python这样做的习惯是newList = oldList[:]

答案 7 :(得分:18)

所有其他贡献者都提供了优秀的答案,当您拥有单个维度(水平)列表时,这些答案有效,但到目前为止提到的方法中,只有copy.deepcopy()可以克隆/当您使用多维嵌套列表(列表列表)时,复制列表并且不指向嵌套的list对象。虽然Felix Kling在他的回答中引用了它,但问题还有一点,可能还有一个使用内置函数的解决方法可能是deepcopy更快的替代方法。

虽然new_list = old_list[:]copy.copy(old_list)'和Py3k old_list.copy()适用于单级列表,但它们会指向嵌套在list内的old_list个对象和new_list,其中一个list对象的更改在另一个中永久存在。

编辑:揭晓新信息

  

正如Aaron HallPM 2Ring所指出的那样使用eval()不仅是一个坏主意,它也比copy.deepcopy()慢得多。

     

这意味着对于多维列表,唯一的选项是copy.deepcopy()。说到这一点,它确实不是一个选项,因为当你尝试在中等大小的多维数组上使用它时,性能会越来越好。我尝试timeit使用42x42阵列,这对于生物信息学应用程序来说并非闻所未闻,甚至是那么大,我放弃了等待回复并开始在此帖子中输入我的编辑。

     

似乎唯一真正的选择是初始化多个列表并独立处理它们。如果有人有任何其他建议,关于如何处理多维列表复制,将不胜感激。

正如其他人所说,使用copy模块 是重要的 性能问题,而{x>} 用于多维列表 即可。

答案 8 :(得分:18)

  

让我们从头开始,探索它有点深:

所以假设你有两个清单:

list_1=['01','98']
list_2=[['01','98']]

我们必须复制这两个列表,现在从第一个列表开始:

首先让我们尝试一般的复制方法:

copy=list_1

现在,如果你认为副本被复制了list_1那么你就错了,让我们检查一下:

The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))

输出:

4329485320
4329485320

很惊讶?好的,让我们探索一下:

因为我们知道python不会在变量中存储任何东西,Variables只是引用对象而对象存储值。这里的对象是list,但是我们通过两个不同的变量名创建了对同一个对象的两个引用。所以这两个变量都指向同一个对象:

所以,当你copy=list_1实际做了什么时:

enter image description here

这里的图像list_1和copy是两个变量名,但两个变量的对象相同,list

因此,如果您尝试修改复制列表,那么它也会修改原始列表,因为列表只有一个,无论您是从复制列表还是从原始列表中修改该列表,都将修改该列表:

copy[0]="modify"

print(copy)
print(list_1)

输出:

['modify', '98']
['modify', '98']

所以它修改了原始列表:

  

那么解决方案是什么?

     

解决方案:

现在让我们转向复制列表的第二种pythonic方法:

copy_1=list_1[:]

现在这个方法解决了我们在第一期中遇到的问题,让我们检查一下:

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

因为我们可以看到我们的两个列表都有不同的id,这意味着两个变量都指向不同的对象,所以这里实际发生的是:

enter image description here

现在让我们尝试修改列表,让我们看看我们是否还面临上一个问题:

copy_1[0]="modify"

print(list_1)
print(copy_1)

输出:

['01', '98']
['modify', '98']

因为你可以看到它没有修改原始列表,它只修改了复制的列表,所以我们对它没问题。

所以现在我觉得我们已经完成了?等等我们也要复制第二个嵌套列表,让我们试试pythonic方式:

copy_2=list_2[:]

因此list_2应该引用另一个对象,它是list_2的副本,让我们检查:

print(id((list_2)),id(copy_2))

我们得到输出:

4330403592 4330403528

现在我们可以假设两个列表都指向不同的对象,所以现在让我们尝试修改它,让它看到它给出了我们想要的东西:

所以当我们尝试:

copy_2[0][1]="modify"

print(list_2,copy_2)

它为我们提供了输出:

[['01', 'modify']] [['01', 'modify']]

现在,我们使用了pythonic方式,这有点令人困惑,但我们仍面临同样的问题。

让我们理解它:

所以当我们这样做时:

copy_2=list_2[:]

我们实际上只复制外部列表,而不是嵌套列表,所以嵌套列表是两个列表的同一对象,让我们检查一下:

print(id(copy_2[0]))
print(id(list_2[0]))

输出:

4329485832
4329485832

所以实际上当我们copy_2=list_2[:]时会发生这种情况:

enter image description here

它创建了列表的副本,但只有外部列表副本,而不是嵌套列表副本,嵌套列表对于这两个变量都是相同的,所以如果你试图修改嵌套列表,那么它也会修改原始列表,因为嵌套列表对象是两个嵌套列表都相同。

那么解决方案是什么?

解决方案是deep copy

from copy import deepcopy
deep=deepcopy(list_2)

现在让我们检查一下:

print(id((list_2)),id(deep))

输出:

4322146056 4322148040

两个ID都不同,现在让我们检查嵌套列表ID:

print(id(deep[0]))
print(id(list_2[0]))

输出:

4322145992
4322145800

正如你可以看到两个id都不同所以我们可以假设两个嵌套列表现在指向不同的对象。

所以当你deep=deepcopy(list_2)实际发生的事情时:

enter image description here

因此,两个嵌套列表都指向不同的对象,并且它们现在具有单独的嵌套列表副本。

现在让我们尝试修改嵌套列表,让我们看看它是否解决了以前的问题:

所以,如果我们这样做:

deep[0][1]="modify"
print(list_2,deep)

输出:

[['01', '98']] [['01', 'modify']]

因为您可以看到它没有修改原始的嵌套列表,所以它只修改了复制的列表。

如果您喜欢我的详细答案,请通过提升来告诉我,  如果您有任何疑问,请回答:)

答案 9 :(得分:17)

Python 3.6时间

以下是使用Python 3.6.8的计时结果。请记住,这些时间是彼此相对的,而不是绝对的。

我坚持只做浅拷贝,并且还添加了一些在Python2中无法实现的新方法,例如list.copy()(Python3 slice equivalent)和两种形式的list unpacking*new_list, = listnew_list = [*list]):

METHOD                  TIME TAKEN
b = [*a]                2.75180600000021
b = a * 1               3.50215399999990
b = a[:]                3.78278899999986  # Python2 winner (see above)
b = a.copy()            4.20556500000020  # Python3 "slice equivalent" (see above)
b = []; b.extend(a)     4.68069800000012
b = a[0:len(a)]         6.84498999999959
*b, = a                 7.54031799999984
b = list(a)             7.75815899999997
b = [i for i in a]      18.4886440000000
b = copy.copy(a)        18.8254879999999
b = []
for item in a:
  b.append(item)        35.4729199999997

我们可以看到Python2获胜者仍然表现不错,但并没有太多地突破Python3 list.copy(),特别是考虑到后者的优越可读性。

黑马是解包和重新打包方法(b = [*a]),比原始切片快约25%,比其他解包方法(*b, = a)快两倍。 / p>

b = a * 1也表现得非常出色。

请注意,这些方法输出除列表以外的任何输入的等效结果。它们都适用于可切片对象,少数适用于任何可迭代,但只有{ {1}}适用于更通用的Python对象。

以下是感兴趣方(Template from here)的测试代码:

copy.copy()

答案 10 :(得分:10)

令我惊讶的是,这还没有被提及,所以为了完整起见...

您可以使用" splat operator":*执行列表解包,这也会复制列表中的元素。

old_list = [1, 2, 3]

new_list = [*old_list]

new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]

这种方法的明显缺点是它只能在Python 3.5 +中使用。

虽然时间明智,但这似乎比其他常用方法表现更好。

x = [random.random() for _ in range(1000)]

%timeit a = list(x)
%timeit a = x.copy()
%timeit a = x[:]

%timeit a = [*x]

#: 2.47 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.47 µs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.39 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

#: 2.22 µs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

答案 11 :(得分:5)

在已经给出的答案中缺少一个独立于python版本的非常简单的方法,你可以在大多数时间使用它(至少我这样做):

new_list = my_list * 1       #Solution 1 when you are not using nested lists

但是,如果my_list包含其他容器(例如嵌套列表),则必须使用深度复制,如上文答案中从复制库中建议的那样。例如:

import copy
new_list = copy.deepcopy(my_list)   #Solution 2 when you are using nested lists

奖金:如果您不想复制元素,请使用(也称为浅版):

new_list = my_list[:]

让我们了解解决方案#1和解决方案#2之间的区别

>>> 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])

正如您所看到的,当我们不使用嵌套列表时,解决方案#1工作正常。让我们检查一下当我们将解决方案#1应用于嵌套列表时会发生什么。

>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]   #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]       #Solution #2 - DeepCopy worked in nested list

答案 12 :(得分:5)

请注意,在某些情况下,如果您已定义自己的自定义类并且希望保留属性,则应使用exec 3<>/file && exec 4</file## gives locks locker() { locked=false while read l; do case "$l" in lock) if $locked; then echo false else locked=true echo true fi ;; unlock) if $locked; then locked=false echo true else echo false fi ;; *) echo false ;; esac done } ## locks lock() { local response echo lock >&${locker[1]} read -ru ${locker[0]} response $response && return 0 || return 1 } ## unlocks unlock() { local response echo unlock >&${locker[1]} read -ru ${locker[0]} response $response && return 0 || return 1 } 而不是替代方法,例如在Python 3中:

copy.copy()

输出:

copy.deepcopy()

答案 13 :(得分:3)

new_list = my_list[:]

new_list = my_list 试着理解这一点。假设my_list位于位置X的堆内存中,即my_list指向X.现在通过分配new_list = my_list,让new_list指向X.这称为浅拷贝。

现在,如果您指定new_list = my_list[:],您只需将my_list的每个对象复制到new_list。这称为深层复制。

你能做到的另一种方式是:

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)

答案 14 :(得分:3)

在执行此操作时,请记住在Python中:

native-image -jar spigot-1.15.jar

List2并不存储实际的列表,而是对list1的引用。因此,当您对list1执行任何操作时,list2也将发生变化。使用复制模块(不是默认值,可从pip下载)来制作列表的原始副本( list1 = ['apples','bananas','pineapples'] list2 = list1 用于简单列表,copy.copy()用于嵌套列表)。这将使副本不会随第一个列表更改。

答案 15 :(得分:1)

这是因为行new_list = my_list为变量my_list分配了一个新引用,该变量为new_list 这类似于下面给出的C代码,

int my_list[] = [1,2,3,4];
int *new_list;
new_list = my_list;

您应该使用复制模块通过以下方式创建新列表

import copy
new_list = copy.deepcopy(my_list)

答案 16 :(得分:1)

使用的方法取决于被复制的列表的内容。如果列表包含嵌套的 dicts,则 deepcopy 是唯一有效的方法,否则答案中列出的大多数方法(切片、循环 [for]、复制、扩展、组合或解包)将在相似的时间(循环和深度复制除外,它们的表现最差)。

脚本

from random import randint
from time import time
import copy

item_count = 100000

def copy_type(l1: list, l2: list):
  if l1 == l2:
    return 'shallow'
  return 'deep'

def run_time(start, end):
  run = end - start
  return int(run * 1000000)

def list_combine(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = [] + l1
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'combine', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

def list_extend(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = []
  l2.extend(l1)
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'extend', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

def list_unpack(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = [*l1]
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'unpack', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

def list_deepcopy(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = copy.deepcopy(l1)
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'deepcopy', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

def list_copy(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = list.copy(l1)
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'copy', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

def list_slice(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = l1[:]
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'slice', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

def list_loop(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = []
  for i in range(len(l1)):
    l2.append(l1[i])
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'loop', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

def list_list(data):
  l1 = [data for i in range(item_count)]
  start = time()
  l2 = list(l1)
  end = time()
  if type(data) == dict:
    l2[0]['test'].append(1)
  elif type(data) == list:
    l2.append(1)
  return {'method': 'list()', 'copy_type': copy_type(l1, l2), 
          'time_µs': run_time(start, end)}

if __name__ == '__main__':
  list_type = [{'list[dict]': {'test': [1, 1]}}, 
          {'list[list]': [1, 1]}]
  store = []
  for data in list_type:
    key = list(data.keys())[0]
    store.append({key: [list_unpack(data[key]), list_extend(data[key]), 
                list_combine(data[key]), list_deepcopy(data[key]), 
                list_copy(data[key]), list_slice(data[key]),           
                list_loop(data[key])]})
  print(store)

结果

[{"list[dict]": [
  {"method": "unpack", "copy_type": "shallow", "time_µs": 56149},
  {"method": "extend", "copy_type": "shallow", "time_µs": 52991},
  {"method": "combine", "copy_type": "shallow", "time_µs": 53726},
  {"method": "deepcopy", "copy_type": "deep", "time_µs": 2702616},
  {"method": "copy", "copy_type": "shallow", "time_µs": 52204},
  {"method": "slice", "copy_type": "shallow", "time_µs": 52223},
  {"method": "loop", "copy_type": "shallow", "time_µs": 836928}]},
{"list[list]": [
  {"method": "unpack", "copy_type": "deep", "time_µs": 52313},
  {"method": "extend", "copy_type": "deep", "time_µs": 52550},
  {"method": "combine", "copy_type": "deep", "time_µs": 53203},
  {"method": "deepcopy", "copy_type": "deep", "time_µs": 2608560},
  {"method": "copy", "copy_type": "deep", "time_µs": 53210},
  {"method": "slice", "copy_type": "deep", "time_µs": 52937},
  {"method": "loop", "copy_type": "deep", "time_µs": 834774}
]}]

答案 17 :(得分:0)

在python中,如果您将值定义为变量,并且将该变量重新分配给另一个变量,

第二个变量仅具有引用,而不具有复制的值。

>>> l = [1,2,3]
>>> k = l
>>> l[0] = 10
>>> l
[10, 2, 3]
>>> k
[10, 2, 3]

因此,如果您更改l&k中的任何内容,都会对两者产生影响。.因此,它们相互参考而不是应对

要使用[::]复制,因此如果您完成分配作业,原始文件不会受到影响。

>>> k = l[::]
>>> k
[10, 2, 3]
>>> l[0] = 100
>>> l
[100, 2, 3]
>>> k
[10, 2, 3]

答案 18 :(得分:0)

我想发布一些与其他答案有些不同的东西。即使这很可能不是最容易理解或最快的选择,它还是提供了有关深层复制工作原理的一些内部视图,并且是深层复制的另一种选择。我的函数是否有错误并不重要,因为这样做的目的是展示一种复制对象(如问题答案)的方法,也可以以此为基础来解释深度复制在其核心的工作原理。

任何深层复制功能的核心是制作浅层复制的方法。怎么样?简单。任何深层复制功能只会复制不可变对象的容器。对嵌套列表进行深度复制时,仅复制外部列表,而不复制列表内部的可变对象。您仅在复制容器。上课也一样。对类进行深度复制时,将对所有可变属性进行深度复制。又怎样?您为什么只需要复制容器,如列表,字典,元组,迭代器,类和类实例?

很简单。可变对象实际上不能被复制。它永远不能更改,因此它只是一个值。这意味着您不必重复字符串,数字,布尔值或任何重复的字符串。但是,您将如何复制容器?简单。您只需使用所有值初始化一个新容器。 Deepcopy依赖于递归。它会复制所有容器,甚至是其中包含容器的容器,直到没有剩余容器为止。容器是一个不变的对象。

一旦您知道,完全复制没有任何引用的对象非常容易。这是一个用于深度复制基本数据类型的函数(不适用于自定义类,但您可以随时添加它)

def deepcopy(x):
  immutables = (str, int, bool, float)
  mutables = (list, dict, tuple)
  if isinstance(x, immutables):
    return x
  elif isinstance(x, mutables):
    if isinstance(x, tuple):
      return tuple(deepcopy(list(x)))
    elif isinstance(x, list):
      return [deepcopy(y) for y in x]
    elif isinstance(x, dict):
      values = [deepcopy(y) for y in list(x.values())]
      keys = list(x.keys())
      return dict(zip(keys, values))

Python自己的内置Deepcopy基于该示例。唯一的区别是,它支持其他类型,并且通过将属性复制到新的重复类中来支持用户类,并且还可以通过使用备忘录列表或字典引用已经看到的对象来阻止无限递归。制作深拷贝确实就是这样。从本质上讲,深层复制只是浅层复制。我希望这个答案可以为这个问题添加一些内容。

示例

假设您有以下列表: [1、2、3] 。不可变的数字不能重复,但是另一层可以重复。您可以使用列表理解来复制它: [x表示[1、2、3]中的x

现在,假设您有以下列表: [[1、2],[3、4],[5、6]] 。这次,您想创建一个函数,该函数使用递归来深度复制列表的所有层。代替先前的列表理解:

[x for x in _list]

它使用一个新的列表:

[deepcopy_list(x) for x in _list]

deepcopy_list 看起来像这样:

def deepcopy_list(x):
  if isinstance(x, (str, bool, float, int)):
    return x
  else:
    return [deepcopy_list(y) for y in x]

现在,您有了一个函数,该函数可以使用递归将 strs,bool,floast,ints 甚至 lists 的任何列表深度复制到无限多个图层。即可进行深度复制。

TLDR :Deepcopy使用递归来复制对象,并且仅返回与以前相同的不可变对象,因为不可变对象无法复制。但是,它会深层复制可变对象的最内层,直到到达对象的最外层可变层。

答案 19 :(得分:0)

从id和gc进入内存的实用角度。


from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPixmap


class Ui_Zertifikat(object):
    def setupUi(self, WindowZertifikat):
        self.myWindowZertifikat = WindowZertifikat
        WindowZertifikat.setObjectName("Form")
        WindowZertifikat.setGeometry(300,300,822,566)

        self.label_Zertifikat1 = QtWidgets.QLabel(WindowZertifikat)
        self.label_Zertifikat1.setGeometry(0,0,822,494)
        self.label_Zertifikat1.setPixmap(QPixmap("./image/speichern.png"))

        self.label_seite1 = QtWidgets.QLabel(self.myWindowZertifikat)
        self.label_seite1.setGeometry(361,495,100,30)
        self.label_seite1.setText("Seite 1 von 2")
        self.label_seite1.setStyleSheet(
        "QLabel{color:Black; font-size:11pt; font-weight:550}"
        )




        self.Button_Zertifikat1 = QtWidgets.QPushButton(self.myWindowZertifikat)
        self.Button_Zertifikat1.setGeometry(422,530,130,30)
        self.Button_Zertifikat1.setText("Nächste Seite")
        self.Button_Zertifikat1.setStyleSheet(
        "QPushButton{background-color: #0000FF; border-width: 2px; border-style: solid; border-color: Black; color:white; font-size:10pt; font-weight:500}"
        "QPushButton:hover{background-color: #08088A; border-width: 2px; border-style: solid; border-color: Black}"
        )

        self.Button_Zertifikat2 = QtWidgets.QPushButton(self.myWindowZertifikat)
        self.Button_Zertifikat2.setGeometry(270,530,130,30)
        self.Button_Zertifikat2.setText("Vorherige Seite")
        self.Button_Zertifikat2.setStyleSheet(
        "QPushButton{background-color: #0000FF; border-width: 2px; border-style: solid; border-color: Black; color:white; font-size:10pt; font-weight:500}"
        "QPushButton:hover{background-color: #08088A; border-width: 2px; border-style: solid; border-color: Black}"
        )    




        self.Button_Zertifikat1.clicked.connect(lambda: self.ZertifikatSeiten(0))
        self.Button_Zertifikat2.clicked.connect(lambda: self.ZertifikatSeiten(1))        


    def ZertifikatSeiten(self, b):
        self.label_Zertifikat2 = QtWidgets.QLabel(self.myWindowZertifikat)
        self.label_Zertifikat2.setGeometry(0,0,822,494)
        self.label_Zertifikat2.setPixmap(QPixmap("./image/umbenennen.png"))

        self.label_Zertifikat1 = QtWidgets.QLabel(self.myWindowZertifikat)
        self.label_Zertifikat1.setGeometry(0,0,822,494)
        self.label_Zertifikat1.setPixmap(QPixmap("./image/speichern.png"))        

        self.label_seite1 = QtWidgets.QLabel(self.myWindowZertifikat)
        self.label_seite1.setGeometry(361,495,100,30)
        self.label_seite1.setText("Seite 1 von 2")
        self.label_seite1.setStyleSheet(
        "QLabel{color:Black; font-size:11pt; font-weight:550}"
        )

        self.label_seite2 = QtWidgets.QLabel(self.myWindowZertifikat)
        self.label_seite2.setGeometry(361,495,100,30)
        self.label_seite2.setText("Seite 2 von 2")
        self.label_seite2.setStyleSheet(
        "QLabel{color:Black; font-size:11pt; font-weight:550}"
        )

        if b == 0:

            self.label_Zertifikat2.show()
            self.label_seite2.show()
            self.label_seite1.hide()



        elif b == 1:

            self.label_Zertifikat1.show()
            self.label_seite1.show()
            self.label_seite2.hide()



if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    WindowZertifikat = QtWidgets.QWidget()
    ui = Ui_Zertifikat()
    ui.setupUi(WindowZertifikat)
    WindowZertifikat.show()
    sys.exit(app.exec_())

答案 20 :(得分:0)

deepcopy选项是唯一适用于我的方法:

from copy import deepcopy

a = [   [ list(range(1, 3)) for i in range(3) ]   ]
b = deepcopy(a)
b[0][1]=[3]
print('Deep:')
print(a)
print(b)
print('-----------------------------')
a = [   [ list(range(1, 3)) for i in range(3) ]   ]
b = a*1
b[0][1]=[3]
print('*1:')
print(a)
print(b)
print('-----------------------------')
a = [   [ list(range(1, 3)) for i in range(3) ] ]
b = a[:]
b[0][1]=[3]
print('Vector copy:')
print(a)
print(b)
print('-----------------------------')
a = [   [ list(range(1, 3)) for i in range(3) ]  ]
b = list(a)
b[0][1]=[3]
print('List copy:')
print(a)
print(b)
print('-----------------------------')
a = [   [ list(range(1, 3)) for i in range(3) ]  ]
b = a.copy()
b[0][1]=[3]
print('.copy():')
print(a)
print(b)
print('-----------------------------')
a = [   [ list(range(1, 3)) for i in range(3) ]  ]
b = a
b[0][1]=[3]
print('Shallow:')
print(a)
print(b)
print('-----------------------------')

导致输出:

Deep:
[[[1, 2], [1, 2], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
*1:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
Vector copy:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
List copy:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
.copy():
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
Shallow:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------

答案 21 :(得分:-1)

复制列表的最简单方法是使用内置的copy()函数,如下所示:

List2 = list1.copy()

这很好用,但这并不是最Python化的方法。

答案 22 :(得分:-1)

有一种简单的技术可以解决这个问题。

代码:

number=[1,2,3,4,5,6] #Original list
another=[] #another empty list
for a in number: #here I am declaring variable (a) as an item in the list (number)
    another.append(a) #here we are adding the items of list (number) to list (another)
print(another)

输出:

>>> [1,2,3,4,5,6]

我希望这对您的查询很有用。

答案 23 :(得分:-1)

还有一种复制直到现在尚未列出的列表的方法:添加一个空列表:l2 = l + []。 我用Python 3.8进行了测试:

l = [1,2,3]
l2 = l + []
print(l,l2)
l[0] = 'a'
print(l,l2)

这不是最好的答案,但是可以。