Python中的赋值语句不会创建一个新对象,它们只是将一个新的变量名称指向原来的对象。
In [1]: a = [1,2,3]
In [2]: b = a
In [3]: b
Out[3]: [1, 2, 3]
In [4]: b is a
Out[4]: True
此时,如果原对象a发生变化, 变量b也同步受到影响。
In [5]: a.append(4)
In [6]: b
Out[6]: [1, 2, 3, 4]
制作拷贝
如果想要生成一个新的对象, 可以使用构造函数
In [1]: a = [1,2,3]
In [2]: b = list(a)
In [3]: b
Out[3]: [1, 2, 3]
In [4]: b is a
Out[4]: False
使用copy函数
In [1]: from copy import copy
In [2]: a = [1,2,3]
In [3]: b = copy(a)
In [4]: b is a
Out[4]: False
对于元素都是不可变的对象, 这样使用没有问题, 如果列表a中的元素包含其他可变对象, 浅拷贝只是在复制的列表中再次被引用。
In [1]: from copy import copy
In [2]: a = [1,2,3]
In [3]: sa = [a, [4, 5, 6]]
In [4]: sb = copy(sa)
In [5]: sb
Out[5]: [[1, 2, 3], [4, 5, 6]]
In [6]: a.append(4)
In [7]: sb
Out[7]: [[1, 2, 3, 4], [4, 5, 6]]
如上例代码中所示, sa是一个二维数组, sb是sa的一个浅拷贝副本, 当对sa中的第一个元素a调用append对a数据进行修改。 同样影响到了sb列表的值。
制作深拷贝
使用copy模块中的deepcopy, 可以解决这个问题。deepcoyp创建的对象的副本将递归克隆子对象。克隆完全独立于原始副本。
In [1]: from copy import deepcopy
In [2]: a = [1,2,3]
In [3]: sa = [a, [4, 5, 6]]
In [4]: sb = deepcopy(sa)
In [5]: sb
Out[5]: [[1, 2, 3], [4, 5, 6]]
In [6]: a.append(4)
In [7]: sb
Out[7]: [[1, 2, 3], [4, 5, 6]]
总结:
- 赋值语句只是增加对原对象的引用
- 制作对象的浅拷贝不会克隆子对象。因此,副本并不完全独立于原件。
- 对象的深层副本将递归克隆子对象。克隆完全独立于原始副本,但创建深层副本的速度较慢。