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