3.6.3. 浅拷贝 与 深拷贝 理解
(浅层复制 与 深层复制 理解)
浅拷贝 shallow copy
深拷贝 deep copy
总结:
浅拷贝: 是指在复制过程中,只复制一层变量绑定关系,不会复制深层变量绑定的对象的复制过程
深拷贝: 对所有可变对象进行层层复制,实现对象的各自独立。
3.6.3.1. 语法及使用方法:
基本语法:
import copy # 导入copy模块
L = "任意类型数据"
L2 = copy.copy(L) # 浅拷贝
L2 = copy.deepcopy(L) # 深拷贝
特别的,在列表中还可以通过切片和自身的copy方法进行浅层复制,如下:
# 浅拷贝
# 1) 利用切片方法。切片——返回切片后的新对象。如
L2 = L[:]
L2 = L[::]
# 2) 利用列表自身方法
L2 = L.copy()
3.6.3.2. 原理理解
浅层复制只复制最外一层的数据或容器对象,内部直接被赋值绑定于新对象对应位置
示例:如何解释Out4和Out5相同,Out9和Out10部分相同,以及后面的测试结果?
In [1]: import copy
In [2]: L = [-10, (-20, -30), [-40, -50, (-60, -70)]]
# 浅拷贝测试
In [3]: X = L.copy()
In [4]: [id(x) for x in L]
Out[4]: [1684750713584, 1684750470920, 1684749580488]
In [5]: [id(x) for x in X]
Out[5]: [1684750713584, 1684750470920, 1684749580488]
In [6]: id(L), id(X)
Out[6]: (1684750584648, 1684750627144)
# 深拷贝测试
In [7]: Y = copy.deepcopy(L)
In [8]: [id(x) for x in L]
Out[8]: [1684750713584, 1684750470920, 1684749580488]
In [9]: [id(x) for x in X]
Out[9]: [1684750713584, 1684750470920, 1684749580488]
In [10]: [id(x) for x in Y]
Out[10]: [1684750713584, 1684750470920, 1684748555272]
# 数据测试
In [11]: L.append("测试1")
In [12]: L[2].append("测试2")
In [13]: L, X, Y
Out[13]:
([-10, (-20, -30), [-40, -50, (-60, -70), '测试2'], '测试1'],
[-10, (-20, -30), [-40, -50, (-60, -70), '测试2']],
[-10, (-20, -30), [-40, -50, (-60, -70)]])
图解:
- 创建L列表
创建3个数据对象,放入列表中(绑定于数据容器对应位置)
L = [-10, (-20, -30), [-40, -50, (-60, -70)]]
绑定关系如下:
# 索引(变量)绑定关系,索引也可看做特殊变量
L[0] L[1] L[2]
| | |
| | |
L = [-10, (-20, -30), [-40, -50, (-60, -70)]]
- 对L浅拷贝绑定X
X = L.copy()
# 或
X = L[::]
# 或 其他...
绑定关系如下:
L[0] L[1] L[2]
| | |
| | |
L = [-10, (-20, -30), [-40, -50, (-60, -70)]]
| | |
| | |
X[0] X[1] X[2]
| | |
| | |
X = [ ]
# 1)重新创建最外层可变数据容器,浅拷贝创建新的最外层对象
# 2)内部所有对象正常赋值绑定
# 绑定原始对象关系,3个数据对象同时被L[N]和L[X]绑定
最外层可变数据容器重新在内存中另一区域开辟创建, 而内一层所有数据对象, 都只是在原来的基础上简单赋值,因而改变最外层新拷贝对象对原始对象无影响,而改变拷贝后的数据对象如X[2],将会使L[2]也同时发生改变
- 对L深拷贝绑定Y
可以简单理解为所有的数据对象全部在内存中拷贝一份,并重新对新数据对象指定绑定关系。
因而,深拷贝后的数据无论如何操作都将不会影响到之前的数据对象,即改变拷贝后的数据对象如Y[2],不会影响L[2]同时发生改变
(不过深拷贝的实际情况为了节省计算机资源,只是复制和重新绑定了新的可变数据对象,而其中不可变的数据对象依然保留,重新赋值绑定,这样节省内存资源的同时亦达到了完全拷贝的同样效果。)
练习:
练习1:
import copy # 导入复制模块
L = [3.1, 3.2]
L1 = [1, 2, L]
L2 = copy.deepcopy(L1) # 实现深拷贝
L[0] = 3.14
print(L1) # _________
print(L2) # _________
# [1, 2, [3.14, 3.2]] #此列表由于浅拷贝受影响
# [1, 2, [3.1, 3.2]] #此列表不受影响
练习2:
import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('c')
print(a) # _________
print(b) # _________
print(c) # _________
print(d) # _________
# [1, 2, 3, 4, ['a', 'b', 'c'], 5]
# [1, 2, 3, 4, ['a', 'b', 'c'], 5]
# [1, 2, 3, 4, ['a', 'b', 'c']]
# [1, 2, 3, 4, ['a', 'b']]
"""解析:
> a: a加了5,a[4]加了'c'
> b: 赋值绑定操作,与a完全一致
> c: 浅拷贝了最外层可变对象,最外层不受影响,但内部可变对象受影响
> d: 深拷贝,所有可变对象不受影响"""