面试的时候被问到“知道浅拷贝和深拷贝吗?”
“…” “os:什么…没听过…”
于是,今天来扒一扒这个知识点。
前提
浅拷贝和深拷贝,其实就是数据拷贝。 - 当拷贝的是不可变数据类型(数值、字符串、元组),不管是深拷贝和浅拷贝,都指向的是同一地址;
import copy
a = 1
b = copy.copy(a)
c = copy.deepcopy(a)
print(a, id(a))
print(b, id(b))
print(c, id(c))
运行结果:
1 4362989344
1 4362989344
1 4362989344
- 当拷贝的对象是可变数据类型(列表、字典),浅拷贝深拷贝才生效。
普通的变量赋值
我们平常使用的变量赋值,就是浅拷贝。即两个变量共享同一个内存块,相同的内存地址,一旦值发生改变,另外一个变量的值也会跟随着一起变化。
li = ['123', 5, 'abc', 9]
a = li
print(id(li))
print(id(a))
a[1] = ['333']
print(id(li), li)
print(id(a), a)
运行结果:
4351771104
4351771104
4330881504 ['123', ['333'], 'abc', 9]
4330881504 ['123', ['333'], 'abc', 9]
常规的变量赋值共享一个代码块,内存地址相同,值发生改变时同一个内存地址的值都会跟着改变。
浅拷贝和深拷贝
copy.copy() – 浅拷贝,重新分配内存,只拷贝父对象,不会拷贝对象的内部的子对象; copy.deepcopy() – 深拷贝,重新分配内存,拷贝对象及其所有子对象;
浅拷贝和深拷贝的区别
- 当拷贝的对象无复杂子对象时:
对于常规的字典或者列表使用copy模块的深拷贝或者浅拷贝,两者并没有区别。
import copy
print('使用浅拷贝:')
a = ['A', 'B', 'C', 'D']
b = copy.copy(a)
b[1] = 42
print(id(a), a)
print(id(b), b)
print('****************************')
print('使用深拷贝:')
a = ['A', 'B', 'C', 'D']
b = copy.deepcopy(a)
b[1] = 42
print(id(a), a)
print(id(b), b)
运行结果:
使用浅拷贝:
4386645008 ['A', 'B', 'C', 'D']
4386646288 ['A', 42, 'C', 'D']
****************************
使用深拷贝:
4386645728 ['A', 'B', 'C', 'D']
4386645008 ['A', 42, 'C', 'D']
- 当字典或者列表中还有包含有子对象时:
使用copy模块的深拷贝和浅拷贝的话,结果就大不相同了。
import copy
print('使用浅拷贝:')
a = ['A', 'B', ['C', 'D', 'E'], 'F']
b = copy.copy(a)
b[2][1] = 42
print(id(a), a)
print(id(b), b)
print('********************************************')
print('使用深拷贝:')
a = ['A', 'B', ['C', 'D', 'E'], 'F']
b = copy.deepcopy(a)
b[2][1] = 42
print(id(a), a)
print(id(b), b)
运行结果:
使用浅拷贝:
4461652240 ['A', 'B', ['C', 42, 'E'], 'F']
4461651680 ['A', 'B', ['C', 42, 'E'], 'F']
*********************************************
使用深拷贝:
4461652000 ['A', 'B', ['C', 'D', 'E'], 'F']
4461652240 ['A', 'B', ['C', 42, 'E'], 'F']
由此可见:
如果列表或者字典没有包含子列表或者子字典的话,使用深拷贝或者浅拷贝效果都有一样;
如果列表或者字典中存在子类的时候,只有深拷贝才会为所有的子类也重新分配内存,而浅拷贝只负责父对象,不考虑子对象。
(原贴:https://cloud.tencent.com/developer/article/1597913)
|