菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
499
0

深浅拷贝

原创
05/13 14:22
阅读数 44034

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 # 如果字典里已经存储了将要拷贝的对象,则直接返回
        ...

发表评论

0/200
499 点赞
0 评论
收藏
为你推荐 换一批