深浅拷贝

Python 中赋值语句不复制对象,而是在目标和对象之间创建绑定 (bindings) 关系。
对于自身可变或者包含可变项的集合对象,开发者有时会需要生成其副本用于改变操作,进而避免改变原对象。

接口摘要:
      copy.copy(x)
      返回 x 的浅层复制。

      copy.deepcopy(x[, memo])
      返回 x 的深层复制。

      exception copy.error
      针对模块特定错误引发
浅层复制和深层复制之间的区别仅与复合对象 (即包含其他对象的对象,如列表或类的实例) 相关:

      一个 浅层复制 会构造一个新的复合对象,然后(在可能的范围内)将原对象中找到的 引用 插入其中。
      一个 深层复制 会构造一个新的复合对象,然后递归地将原始对象中所找到的对象的 副本 插入。

深度复制操作通常存在两个问题, 而浅层复制操作并不存在这些问题:
      递归对象 (直接或间接包含对自身引用的复合对象) 可能会导致递归循环。①
      由于深层复制会复制所有内容,因此可能会过多复制(例如本应该在副本之间共享的数据)。

对上面①的解释
如果被拷贝对象中存在指向自身的引用,那么程序很容易陷入无限循环,例如:

>>> import copy
>>> list1 = [1]
>>> list1.append(list1)
>>> list1
[1, [...]]

>>> list2 = copy.deepcopy(list1)
>>> list2
[1, [...]]

因为深度拷贝函数 deepcopy 中会维护一个字典,记录已经拷贝的对象与其 ID。
拷贝过程中,如果字典里已经存储了将要拷贝的对象,则会从字典直接返回。通过查看 deepcopy 函数实现的源码就会明白:

def deepcopy(x, memo=None, _nil=[]):
    """Deep copy operation on arbitrary Python objects.
    See the module's __doc__ string for more info.
    """
   
    if memo is None:
        memo = {}
    d = id(x) # 查询被拷贝对象 x 的 id
    y = memo.get(d, _nil) # 查询字典里是否已经存储了该对象
    if y is not _nil:
        return y # 如果字典里已经存储了将要拷贝的对象,则直接返回
        ...
posted @ 2021-02-01 16:04  EdenWu  阅读(57)  评论(0编辑  收藏  举报