Skip to content

copy 模块

浅拷贝的局限性 (Limitation of Shallow Copy)

copy() 方法不会递归地创建子对象的副本,因此如果子对象是可变的(例如嵌套列表),对子对象的任何修改都会反映在父对象和其副本中。

python
>>> old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

#将旧列表复制到新列表 (浅拷贝)
>>> new_list = old_list.copy()

#检查两个列表是否指向同一个对象 (False,列表本身是新的)
>>> id(new_list)==id(old_list)
False

#检查两个列表的项是否指向相同的对象 (True,子列表是共享的)
>>> [id(new_list[idx])==id(old_list[idx]) for idx in range(len(old_list))]
[True, True, True]

#修改新列表的子列表
>>> new_list[1][1] = 0
>>> new_list
[[1, 2, 3], [4, 0, 6], [7, 8, 9]]
>>> old_list # old_list 也被修改了
[[1, 2, 3], [4, 0, 6], [7, 8, 9]]

正如我们在输出中看到的,修改了 new_list[1][1],这同时反映在 new_listold_list 中。

copy 模块提供了 deepcopy() 函数,有助于缓解此问题。

深拷贝 - deepcopy(x[, memo]) (Deep Copy - deepcopy(x[, memo]))

深拷贝克服了 copy() 的缺点,并递归地创建原始列表中找到的子对象的副本。这导致创建了原始对象的独立副本。

python
>>> import copy
>>> old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

#将旧列表深拷贝到新列表
>>> new_list = copy.deepcopy(old_list)

#检查两个列表是否指向同一个对象 (False)
>>> id(new_list)==id(old_list)
False

#检查两个列表的项是否指向相同的对象 (False,子列表也是新的)
>>> [id(new_list[idx])==id(old_list[idx]) for idx in range(len(old_list))]
[False, False, False]

#修改新列表的子列表
>>> new_list[1][1] = 0
>>> new_list
[[1, 2, 3], [4, 0, 6], [7, 8, 9]]
>>> old_list # old_list 未被修改
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

注意子项的 id() 相等性从 [True, True, True] 变为 [False, False, False]。正如我们在输出中看到的,修改了 new_list[1][1],这仅反映在 new_list 中。