首页 文章

如何克隆或复制列表?

提问于
浏览
1865

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

使用 new_list = my_list 然后每次 my_list 更改时修改 new_list .
为什么是这样?

19 回答

  • 4

    使用 thing[:]

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

    Python 3.6.0计时

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

    我坚持只做浅拷贝,并且还添加了Python2中不可能的一些新方法,例如 list.copy() (Python3 slice equivalent)和list unpacking*new_list, = list ):

    METHOD                  TIME TAKEN
    b = a[:]                6.468942025996512   #Python2 winner
    b = a.copy()            6.986593422974693   #Python3 "slice equivalent"
    b = []; b.extend(a)     7.309216841997113
    b = a[0:len(a)]         10.916740721993847
    *b, = a                 11.046738261007704
    b = list(a)             11.761539687984623
    b = [i for i in a]      24.66165203397395
    b = copy.copy(a)        30.853400873980718
    b = []
    for item in a:
      b.append(item)        48.19176080400939
    

    考虑到Python3 list.copy() 方法的可读性增加,我们可以看到老赢家仍然名列前茅,但实际上并不是很大 .

    Note that these methods do not output equivalent results for any input other than lists. 它们都适用于可切片对象,一些适用于任何可迭代对象,但只有 copy.copy() 适用于任何Python对象 .


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

    import timeit
    
    COUNT = 50000000
    print("Array duplicating. Tests run", COUNT, "times")
    setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'
    
    print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
    print("b = copy.copy(a)\t\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
    print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
    print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
    print("b = a[0:len(a)]\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
    print("*b, = a\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
    print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
    print("b = []\nfor item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a:  b.append(item)', setup=setup, number=COUNT))
    print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))
    
  • 0

    been told那是Python 3.3 adds list.copy()方法,它应该和切片一样快:

    newlist = old_list.copy()

  • 4

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

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

    • 您可以使用builtin 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)
    
    import copy
    new_list = copy.copy(old_list)
    

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

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

    显然是最慢和最需要内存的方法,但有时是不可避免的 .

    Example:

    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]
    
  • 17

    你可以在list()函数中使用bulit:

    newlist=list(oldlist)
    

    我认为这段代码会对你有所帮助 .

  • 8

    您将使用python标准库中的deepcopy .

    在python中,当您复制数据类型时,原始数据类型和复制数据类型为 share the same memory locations . 因此, any changes made to a copy of object gets reflected in the original object . 例如,考虑一下:

    my_lst=[1,2,3,4,5] #Python list
    print my_lst, ' my_lst (before copy)'
    
    my_lst_copy = my_lst=[1,2,3,4,5] #Simple copy of python list
    my_lst_copy[2] = 55 #Copy of python list changed
    
    print my_lst_copy, ' my_lst_copy (copy of python list)'
    print my_lst, ' my_lst (after copy)'
    
    >>>[1, 2, 3, 4, 5]  my_lst (before copy)
    >>>[1, 2, 55, 4, 5]  my_lst_copy (copy of python list)
    >>>[1, 2, 55, 4, 5]  my_lst (after copy)
    

    正如您之前注意到的那样,并且在上面的示例中再次注意到,更改复制列表的任何元素 my_list_cp 会更改原始列表 my_list . 这样做的原因是 my_list_cp 没有新的任务 .

    您可以使用python标准库中的deepcopy来抵消上述情况 . 在深层复制中,对象的副本将复制到其他对象中 .

    from copy import deepcopy
    
    my_lst=[1,2,3,4,5] #Python list
    print my_lst, ' my_lst (before copy)'
    
    my_lst_copy = deepcopy(my_lst) #Python list copied
    my_lst_copy[2] = 55 #Copy of python list changed
    
    print my_lst_copy, ' my_lst_copy (copy of python list)'
    print my_lst, ' my_lst (after copy)'
    
    >>>[1, 2, 3, 4, 5]  my_lst (before copy)
    >>>[1, 2, 55, 4, 5]  my_lst_copy (copy of python list)
    >>>[1, 2, 3, 4, 5]  my_lst (after copy)
    

    在上面的示例中,您看到复制后 my_lst 未更改 .

  • 2547

    请注意,在某些情况下,如果您已经定义了自己的自定义类并且想要保留属性,那么您应该使用 copy.copy()copy.deepcopy() 而不是替代方法,例如在Python 3中:

    import copy
    
    class MyList(list):
        pass
    
    lst = MyList([1,2,3])
    
    lst.name = 'custom list'
    
    d = {
    'original': lst,
    'slicecopy' : lst[:],
    'lstcopy' : lst.copy(),
    'copycopy': copy.copy(lst),
    'deepcopy': copy.deepcopy(lst)
    }
    
    
    for k,v in d.items():
        print('lst: {}'.format(k), end=', ')
        try:
            name = v.name
        except AttributeError:
            name = 'NA'
        print('name: {}'.format(name))
    

    输出:

    lst: original, name: custom list
    lst: slicecopy, name: NA
    lst: lstcopy, name: NA
    lst: copycopy, name: custom list
    lst: deepcopy, name: custom list
    
  • 27
    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)

  • 32

    不确定这是否仍然是实际的,但同样的行为也适用于字典 . 看看这个例子 .

    a = {'par' : [1,21,3], 'sar' : [5,6,8]}
    b = a
    c = a.copy()
    a['har'] = [1,2,3]
    
    a
    Out[14]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}
    
    b
    Out[15]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}
    
    c
    Out[16]: {'par': [1, 21, 3], 'sar': [5, 6, 8]}
    
  • 4

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

    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 .

  • 123

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

    您可以使用"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)
    
  • 13

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

    • 10.59秒(105.9us / itn) - copy.deepcopy(old_list)

    • 10.16秒(101.6us / itn) - 使用deepcopy复制类的纯python Copy() 方法

    • 1.488秒(14.88us / itn) - 纯python Copy() 方法不复制类(只有dicts / lists / tuples)

    • 0.325秒(3.25us / itn) - for item in old_list: new_list.append(item)

    • 0.217秒(2.17us / itn) - [i for i in old_list] (a list comprehension

    • 0.186秒(1.86us / itn) - copy.copy(old_list)

    • 0.075秒(0.75us / itn) - list(old_list)

    • 0.053秒(0.53us / itn) - new_list = []; new_list.extend(old_list)

    • 0.039秒(0.39us / itn) - old_list[:]list slicing

    所以最快的是列表切片 . 但要注意 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
    

    EDIT :在基准测试中添加了新式的旧式类和dicts,并使python版本更快,并添加了更多方法,包括列表表达式和 extend() .

  • 3

    Python的成语是 newList = oldList[:]

  • 479

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

    所以假设你有两个清单:

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

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

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

    copy=list_1
    

    现在如果您认为复制复制了list_1那么您可能错了,让我们检查一下:

    id()函数向我们显示两个变量都指向同一个列表对象,即它们共享此对象 .

    print(id(copy))
    print(id(list_1))
    

    输出:

    4329485320
    4329485320
    

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

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

    所以当你做 copy=list_1 实际上它在做什么:

    这里的图像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,这意味着两个变量都指向不同的对象,所以这里实际发生的是:

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

    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[:] 时会发生这种情况:

    它创建列表的副本,但只有外部列表副本,而不是嵌套列表副本,嵌套列表对于两个变量都是相同的,因此如果您尝试修改嵌套列表,那么它也将修改原始列表,因为嵌套列表对象对于两者都是相同的嵌套列表 .

    那么解决方案是什么?

    解决方案是 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) 实际发生的事情:

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

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

    所以如果我们这样做:

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

    输出:

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

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

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

  • 5

    在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'], [], []]
    

    因此,我们看到深层复制列表与原始列表完全不同 . 你可以自己动手 - 但不要 . 您可能会使用标准库的deepcopy函数创建您不会遇到的错误 .

    不要使用eval

    你可能会看到这被用作深度复制的一种方法,但是不要这样做:

    problematic_deep_copy = eval(repr(a_list))
    
    • 它's dangerous, particularly if you'从你不信任的来源评估一些东西 .

    • 它's not reliable, if a subelement you'重新复制doesn 't have a representation that can be eval' d以重现等效元素 .

    • 性能也不太好 .

    在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
    
  • 95

    所有其他贡献者给出了 great 答案,当你有一个维度(水平)列表时,它可以工作,但是到目前为止提到的方法中,只有 copy.deepcopy() 用于克隆/复制列表而不是指向嵌套的 list 对象时您正在使用多维嵌套列表(列表列表) . 虽然Felix Kling在他的回答中引用了它,但问题还有一点,可能使用内置函数的解决方法可能是 deepcopy 的更快替代方案 .

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

    编辑:新信息曝光

    正如Aaron Hall和PM 2Ring指出的那样使用eval()不仅是一个坏主意,它也比copy.deepcopy()慢得多 . 这意味着对于多维列表,唯一的选择是copy.deepcopy() . 说到这一点,当你尝试在中等大小的多维数组上使用它时,它实际上不是一个选项 . 我尝试使用42x42阵列进行计时,这对于生物信息学应用来说并不是闻所未闻,甚至是那么大,我放弃了等待响应并开始在这篇文章中输入我的编辑 . 似乎唯一真正的选择是初始化多个列表并独立地处理它们 . 如果有人有任何其他建议,对于如何处理多维列表复制,将不胜感激 .

    正如其他人所说,使用 copy 模块和 copy.deepcopy for multidimensional lists 可能会出现 are significant 性能问题 . 尝试在不使用深度复制的情况下计算出复制多维列表的不同方法(我正在研究一个课程的问题,只允许整个算法运行5秒才能获得信用),我想出了一个方法使用内置函数制作嵌套列表的副本,而不是将它们指向彼此或嵌套在它们中的列表对象 . 我在赋值中使用了eval()和repr()来将旧列表的副本放入新列表中,而不创建旧列表的链接 . 它采取以下形式:
    new_list = eval(repr(old_list))
    基本上,它的作用是将old_list表示为字符串,然后将字符串计算为字符串所代表的对象 . 通过这样做,不会链接到原始列表对象 . 创建一个新的列表对象,每个变量指向它自己的独立对象 . 以下是使用二维嵌套列表的示例 . 对于范围(x)中的i,old_list = [[0表示范围(y)中的j]] #initialize(x,y)嵌套列表

    #将old_list的副本分配给新列表,而不指向同一列表对象
    new_list = eval(repr(old_list))

    #对new_list进行更改
    对于范围内的j(y):
    对于范围(x)中的i:
    new_list [i] [j] = 1
    如果您然后检查每个列表的内容,例如4乘3列表,Python将返回>>> new_list

    [[1,1,1],[1,1,1],[1,1,1],[1,1,1]]

    old_list

    [[0,0,0],[0,0,0],[0,0,0],[0,0,0]]
    虽然这可能不是规范或语法上正确的方法,但它似乎运作良好 . 我没有测试过性能,但我猜测eval()和rep()的开销会减少运行比deepcopy会 .

  • 14

    new_list = list(old_list)

  • 44

    一个非常简单的方法独立于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
    

    . Bonus :如果你不想复制元素使用(又称浅拷贝):

    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
    
  • 29

    与其他具有 variable and value 的语言不同,Python具有 name and object .

    这个说法:

    a = [1,2,3]
    

    意味着给列表(对象)一个名称 a ,并且:

    b = a
    

    只是给同一个对象 a 一个新名称 b ,所以无论何时你用 a 做什么,对象都会改变,因此 b 会改变 .

    制作一个 really 副本的唯一方法是 create a new object 就像其他答案已经说过的那样 .

    你可以看到更多关于这个here的信息 .

相关问题