复制列表等多数内置可变集合,最简单的就是使用内置的构造方法。当然也可以使用 l2=l1[:] 来复制。
>>> l1 = [3, [55, 44], (7, 8, 9)]
>>> l2 = list(l1)
>>> l2
[3, [55, 44], (7, 8, 9)]
>>> l2 == l1
True
>>> l2 is l1
False然而,构造方法或 [:] 做的是浅复制(即复制了最外层容器,副本中的元素是源容器中元素的引用)。
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = list(l1) # 浅拷贝
l1.append(100) # 不会影响到 l2
l1[1].remove(55) # l1、l2 第一个元素都 remove 55
print('l1:', l1) # [3, [66, 44], (7, 8, 9), 100]
print('l2:', l2) # [3, [66, 44], (7, 8, 9)]
l2[1]+= [33, 22] # 赋值操作,改变 l1、l2 第一个元素
l2[2]+= (10, 11) # 赋值操作,改变 l2 第二个元素
print('l1:', l1) # [3, [66, 44, 33, 22], (7, 8, 9), 100]
print('l2:', l2) # [3, [66, 44, 33, 22], (7, 8, 9, 10, 11)]使用 Python Tutor 网站可以查看动画效果。
这里,还需要关注的是 += 操作。
- 对于可变对象来说,
+=运算符是就地修改列表。 - 对于元组来说,
+=运算符是创建一个新元组,然后绑定。
如果想要进行深拷贝,使用 copy 模块。copy 模块提供了 deepcopy 和 copy 函数能为任何对象提供深拷贝和浅拷贝。这两个函数分别使用了对象默认的 __copy__() 和 __deepcopy__() 函数来进行拷贝。因此,可以更改对象对应函数来控制拷贝的具体行为。
deepcopy 能对存在自身引用的对象进行深拷贝的原因:内部维护一个字典,通过 id 判断对象。