Python中的深拷贝与浅拷贝
定义:所谓浅拷贝就是对引用的拷贝;所谓深拷贝就是对对象的资源的拷贝。
1、对于直接赋值(=),有如下三点认识:
1)、赋值是将一个对象的地址赋值给一个变量,让变量指向该地址(旧瓶装旧酒)。
2)、修改不可变对象(str、tuple)需要开辟新的空间
3)、修改可变对象(list等)不需要开辟新的空间
- 浅拷贝仅仅复制了容器中元素的地址
#对于赋值运算,就是指向同一个内存地址. s1 = 'alex' s2 = s1 print(s1, id(s1)) #alex 1996081840344 print(s2, id(s2)) #alex 1996081840344
#当s1的值修改时,内存地址也发生了变化 s1 = 'alex' print(s1, id(s1)) #alex 1515050615000 s1 = 'alex2' print(s1, id(s1)) #alex 1515051454624
#当列表l1新增一个值,其内存地址不变 l1 = [1,2,3] l2 = l1 print(l1, id(l1)) #[1, 2, 3] 1730542337864 print(l2, id(l2)) #[1, 2, 3] 1730542337864 l1.append(4) print(l1, id(l1)) #[1, 2, 3, 4] 1730542337864 print(l2, id(l2)) #[1, 2, 3, 4] 1730542337864
2、copy浅拷贝,只拷贝父对象,没拷贝子对象,所以原始数据改变,子对象会改变
#切片赋值相当于浅copy,只拷贝值,不拷贝内存地址 l1 = [1,2,3] l2 = l1[:] print(l1, id(l1)) #[1, 2, 3] 2685913624392 print(l2, id(l2)) #[1, 2, 3] 2685913645192 l1.append(4) print(l1, id(l1)) #[1, 2, 3, 4] 2685913624392 print(l2, id(l2)) #[1, 2, 3] 2685913645192
#只拷贝父对象第一次的值,不拷贝内存地址 l1 = [1,2,3] l2 = l1.copy() l1.append(666) print(l1, id(l1)) #[1, 2, 3, 666] 2170284179272 print(l2, id(l2)) #[1, 2, 3] 2170284195976
#对于浅copy来说,第一层都是独立的内存地址,从第二层开始,都是指向同一个内存地址,一变都变 l1 = [1,2,3,[22,33]] l2 = l1.copy() l1[3].append(666) print(l1, id(l1)) #[1, 2, 3, [22, 33, 666]] 1643848253576 print(l2, id(l2)) #[1, 2, 3, [22, 33, 666]] 1643848253704
3、deepcopy深拷贝,包含父对象及其子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
#对于深copy来说,无论多少层,在内存中都是两个独立的内存地址 import copy #引入copy模块 l1 = [1,[22,33]] l2 = copy.deepcopy(l1) l1.append(77) l1[1].append(66) print(l1, id(l1), id(l1[1])) #[1, [22, 33, 66], 77] 1756548727112 1756548726920 print(l2, id(l2), id(l2[1])) #[1, [22, 33]] 1756548728392 1756548728328
总结:
1、深浅拷贝都是对源对象的复制,占用不同的内存空间。
2、不可变类型(数字、字符串、元组)的对象,对于深浅拷贝毫无影响,最终的地址值和值都是相等的。
3、可变类型(列表、字典):
=浅拷贝: 值相等,地址相等
copy浅拷贝:值相等,地址不相等
deepcopy深拷贝:值相等,地址不相等