深拷贝和浅拷贝
在 Python
中通常将值赋值个某个变量时,实际上是这个值的内存地址指向了该变量,变量就相当是这个值的内存地址的一个引用.
例如:
>>> L = [11, 22, 33, 44, 55]
>>> new_L = L
>>> new_L
[11, 22, 33, 44, 55]
>>> L.append(66)
>>> L
[11, 22, 33, 44, 55, 66]
>>> new_L
[11, 22, 33, 44, 55, 66]
>>> L == new_L
True
>>> L is new_L
True
>>> id(L)
1968629268616
>>> id(new_L)
1968629268616
在上面的示例中,可以看出,当 L
赋值给 new_L
时,实际上就是在 [11, 22, 33, 44, 55]
的内存地址上创建了一个新的引用 new_L
,所以 new_L
实际上还是指向的 [11, 22, 33, 44, 55]
,它并没有创建一个新的内存地址.这就是浅拷贝,浅拷贝不会开辟新的内存空间,而是在原有的内存地址上创建一个新的指向该内存地址的变量.
同样是是一个示例:
# 导入一个 copy 包
>>> import copy
>>> L = [11, 22, 33, 44, 55]
>>> new_L = copy.deepcopy(L)
# 查看这两个的 id
>>> id(L)
1968629268616
>>> id(new_L)
1968629839752
>>> L.append(66)
>>> L
[11, 22, 33, 44, 55, 66]
>>> new_L
[11, 22, 33, 44, 55]
>>> L == new_L
False
>>> L is new_L
False
同样时拷贝,在使用 copy 模块后,结果就变得与上面的不同了,因为在使用了 copy.deepcopy
后就变成深拷贝了,深拷贝不再只在原有的内存地址上创建一个新的引用了,而是开辟了一个新的内存空间,并将新的变量指向该内存空间,这样使得拷贝后的值不再和原有值的内存地址相同了.
深拷贝还可以拷贝多层引用,通俗的讲就是不管有几层引用,最后都会找到最终的那个内存地址,并进行拷贝.
例如:
>>> import copy
>>> A = [11, 22, 33]
>>> B = [44, 55, 66]
>>> C = [A, B]
>>> D = copy.deepcopy(C)
>>> E = C
>>> id(C)
1968629863304
>>> id(D)
1968629268680
>>> id(E)
1968629863304
>>> C is D
False
>>> A.append(55)
>>> A
[11, 22, 33, 55]
>>> C
[[11, 22, 33, 55], [44, 55, 66]]
>>> D
[[11, 22, 33], [44, 55, 66]]
在上面的列表 C 中,不是传入的具体的值,而是 A/B 变量,相当于传入的时两个引用,而不是具体的内存地址, D 是 C深拷贝后的值,由后面的验证可以看出 D 还是开辟了一个新的内存空间, 虽然 C 列表中只有两个地址的引用,但是深拷贝还是通过 C 列表中的变量找到了更上一级的内存地址.