【问题标题】:In Python, what's the difference between deepcopy and [each[:] for each in List]在 Python 中,deepcopy 和 [each[:] for each in List] 有什么区别?
【发布时间】:2016-10-11 11:58:42
【问题描述】:

下面是示例代码:

from copy import deepcopy
List = [range(3), range(3), range(3)]
a = deepcopy(List)
b = [each[:] for each in List]

我知道初始化 a 所需的时间比 b 的时间要慢,但是为什么会这样呢? deepcopy 和 [each[:] for each in List] 有什么区别?为什么 deepcopy 这么慢?

【问题讨论】:

    标签: python list copy deep-copy


    【解决方案1】:

    each[:] 创建每个嵌套列表的浅层 副本。 copy.deepcopy() 会制作一个副本。

    在这种特定情况下,您的嵌套列表包含不可变整数,这种差异实际上并不重要; deepcopy() 在复制时返回整数不变。但如果嵌套列表中有 可变 对象,那么 deepcopy() 将继续创建这些对象的副本,而您的列表理解则不会。

    例如,在复制包含带有字典的列表的列表时,您会看到不同之处:

    >>> from copy import deepcopy
    >>> sample = [[{'foo': 'bar'}, {'ham': 'spam'}], [{'monty': 'python'}, {'eric': 'idle'}]]
    >>> shallow = [each[:] for each in sample]
    >>> deep = deepcopy(sample)
    >>> sample[-1][-1]['john'] = 'cleese'
    >>> sample
    [[{'foo': 'bar'}, {'ham': 'spam'}], [{'monty': 'python'}, {'eric': 'idle', 'john': 'cleese'}]]
    >>> shallow
    [[{'foo': 'bar'}, {'ham': 'spam'}], [{'monty': 'python'}, {'eric': 'idle', 'john': 'cleese'}]]
    >>> deep
    [[{'foo': 'bar'}, {'ham': 'spam'}], [{'monty': 'python'}, {'eric': 'idle'}]]
    

    因为deepcopy() 操作必须测试嵌套列表中的每个元素,所以它也比较慢;如果您知道不需要生成“更深”的副本,则列表推导是更好的选择。

    【讨论】:

      【解决方案2】:

      正如 Martijn Pieters 所说, each[:] 将通过创建每个嵌套列表的浅表副本来执行。如果您的列表元素是不可变对象,那么您可以使用它,否则您必须使用复制模块中的 deepcopy。

      可以使用切片运算符完全复制浅表结构而不会产生任何副作用,请查看以下快照:

      LIST_1 = ['A','B',['AB','BA']]
      print LIST_1
      >>> ['A', 'B', ['AB', 'BA']]
      LIST_2= LIST_1[:]
      print id(LIST_1)
      >>> 40427648
      print id(LIST_2)
      >>> 50932872  
      LIST_2[2][1] = "D"
      LIST_2[2][0] = "C";
      
      print LIST_2
      >>> ['A', 'B', ['C', 'D']] 
      print LIST_1
      >>> ['A', 'B', ['C', 'D']] 
      

      但是在 deepcopy 方法中:

      解决上述问题的方法是使用“复制”模块。这个模块提供了方法“copy”,它允许一个任意列表的完整副本,即浅表和其他列表。所以你使用copy.deepcopy(...) 来深度复制一个列表:

      deepcopy(x, memo=None, _nil=[])
      

      下面的脚本使用我们上面的例子和这个方法:

      from copy import deepcopy
      
      LIST_1 = ['A','B',['AB','BA']]
      
      LIST_2= deepcopy(LIST_1)
      
      LIST_2[2][1] = "D"
      LIST_2[0] = "C";
      
      print LIST_2
      >>>['C', 'B', ['AB', 'D']]
      print LIST_1
      >>>['A', 'B', ['AB', 'BA']]
      

      因此,每个嵌套列表的浅表副本不会递归地复制内部对象。它只复制最外面的列表,同时仍然从前一个变量引用内部列表,这就是 deepcopy 速度较慢的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-12
        • 1970-01-01
        • 1970-01-01
        • 2011-09-30
        • 2016-06-11
        • 1970-01-01
        • 2016-12-16
        • 1970-01-01
        相关资源
        最近更新 更多