【问题标题】:What is the best way to copy a list? [duplicate]复制列表的最佳方法是什么? [复制]
【发布时间】:2010-09-16 03:01:27
【问题描述】:

复制列表的最佳方法是什么?我知道以下几种方法,哪一种更好?还是有别的办法?

lst = ['one', 2, 3]

lst1 = list(lst)

lst2 = lst[:]

import copy
lst3 = copy.copy(lst)

【问题讨论】:

    标签: python


    【解决方案1】:

    如果您想要浅拷贝(不拷贝元素),请使用:

    lst2=lst1[:]
    

    如果要进行深拷贝,请使用复制模块:

    import copy
    lst2=copy.deepcopy(lst1)
    

    【讨论】:

    • 不复制元素是什么意思?
    • 如果元素是通过引用传递的可变对象,则必须使用 deepcopy 才能真正复制它们。
    • 它只会复制列表中的引用。如果列表中的元素包含对另一个对象的引用,则不会被复制。 10 次中有 9 次你只需要浅拷贝。
    • 更清晰的方法是:lst2 = list (lst1)
    【解决方案2】:

    我经常使用:

    lst2 = lst1 * 1
    

    如果 lst1 它包含其他容器(如其他列表),您应该使用复制库中的 deepcopy,如 Mark 所示。


    更新:解释 deepcopy

    >>> 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] 是同一个对象。 现在用 deepcopy 试试吧

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

    【讨论】:

    • copy() 在最后一种情况下不起作用,只要对象内部有引用,就需要deepcopy()
    • 我认为你使用lst1*1 的技巧非常好......但是,可悲的是,粗略的分析表明它至少比lst1[:] 慢两倍,这比@ 稍快987654330@.
    【解决方案3】:

    你也可以这样做:

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

    【讨论】:

    • 结果是浅拷贝还是深拷贝?
    • 不,使用 list() 绝对是浅拷贝。试试看。
    • 有速度差异吗?可以说,当您执行[:] 时,该库足够聪明,可以知道正在制作副本,因此它可能会调用一些本机 C 代码来执行此操作。使用list(iterable),它是否知道/关心迭代已经物化,因此可以有效地复制?
    • 那么,使用 copy 模块获取列表的深拷贝是唯一的方法吗? Python 的标准功能中没有包含深拷贝,这似乎很奇怪。
    【解决方案4】:

    我喜欢做:

    lst2 = list(lst1)
    

    与 lst1[:] 相比的优势在于相同的成语适用于 dicts:

    dct2 = dict(dct1)
    

    【讨论】:

    【解决方案5】:

    短名单,[:] 是最好的:

    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
    

    对于非常大的列表(我尝试了 50MM),它们仍然大致相同。

    【讨论】:

    • 如果我必须在 100 行代码之间做一个副本,我不会打扰。只有当它是应用程序的核心部分并且列表复制频繁时,我才可能会打扰。
    【解决方案6】:

    您也可以这样做:

    import copy
    list2 = copy.copy(list1)
    

    这应该和 Mark Roddy 的浅拷贝一样。

    【讨论】:

      【解决方案7】:

      就性能而言,调用list() 与切片相比有一些开销。所以对于短名单,lst2 = lst1[:] 的速度大约是lst2 = list(lst1) 的两倍。

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

      【讨论】:

        猜你喜欢
        • 2014-01-15
        • 1970-01-01
        • 2017-08-23
        • 2012-04-22
        • 2011-10-22
        • 2010-09-05
        • 1970-01-01
        • 2010-12-05
        • 1970-01-01
        相关资源
        最近更新 更多