在python中,由于共享内存导致copy有深copy和浅copy之分,大家稍有不注意就可能会改变不希望被改变的信息。
浅copy
数据“半共享”
- 可以浅copy的数据类型:list、dict、set
Q:何为浅copy?
A:只能copy最浅层(即第一层),不能copy数据类型中嵌套的数据类型
在python 中 id()
方法可以查看存放变量的内存地址,这为我们下面理解深浅copy提供了便利。
不多说,上码:
>>> a = [1,[23,4],3]
>>> a
[1, [23, 4], 3]
>>> b = a.copy()
>>> b
[1, [23, 4], 3]
>>> b[0]=2
>>> b
[2, [23, 4], 3]
>>> a
[1, [23, 4], 3]
>>> b[1][1]=234234 #更改列表中嵌套的二级列表
>>> b
[2, [23, 234234], 3]
>>> a #原列表也会被更改
[1, [23, 234234], 3]
>>> id(a)
2198613584328
>>> id(b)
2198613596744
>>> id(a[0])
140710427074960
>>> id(b[0])
140710427074992 #对于改变的元素,地址也会变
>>> id(b[1])
2198613584904 #b中嵌套的二级列表地址
>>> id(a[1])
2198613584904 #原列表中嵌套的二级列表地址,可看出和copy的地址一致
>>> id(a[2])
140710427075024
>>> id(b[2])
140710427075024 #对于没有改变的元素,地址与原列表地址一致
从代码可以看出:改变b中嵌套的二级列表会影响a中的二级列表。
Q:为什么二级列表里的数值被更改了?
A:浅copy时,内存会开辟一个新的空间存放一个新的列表,列表中的元素和元素地址都会被copy过来,但可变数据类型(二级列表)被当做一个整体不被copy,所以二级列表的地址也和原列表的地址保持一致,即对二级列表中的元素更改时,a和b会相互影响,元素永远相同。
而一级列表中的不可变数据类型,虽然元素与地址都被复制过来,但两者进行修改时不会相互影响,并且修改后地址会变得不一致。而在一级列表添加新的元素时,两者同样不会相互影响,只要不改变copy过来的元素,地址会一直与copy过来的一致。
dict和set也是如此。
深copy
copy所有内容。深copy后改变其内容不会对原数据产生任何影响。
深copy需要导入python自带的库——copy。
上码:
>>> import copy
>>> a = [1,[23,4],3]
>>> b = copy.deepcopy(a)
>>> b
[1, [23, 4], 3]
>>> b[0] = 2
>>> b
[2, [23, 4], 3]
>>> a
[1, [23, 4], 3]
>>> b[1][1] = 234234
>>> b
[2, [23, 234234], 3]
>>> a
[1, [23, 4], 3]
>>> id(a)
2198613756168
>>> id(b)
2198613785864
>>> id(a[0])
140710427074960
>>> id(b[0])
140710427074992 #对于改变的元素,地址会改变
>>> id(a[1])
2198613756744 #原列表中嵌套的二级列表地址
>>> id(b[1])
2198613785288 #b中嵌套的二级列表地址,可看出和原列表中嵌套的二级列表地址不一致
>>> id(a[2])
140710427075024
>>> id(b[2])
140710427075024 #对于没有改变的元素,地址与原列表地址一致
从代码可以看出:a,b互不影响。
浅析深浅copy
深copy是拷贝所有内容。包括内部(二级列表)的所有,形成一个新的对象,虽然与之前的值和内容一模一样,但是它们时完完全全的两个对象,二级列表的地址同样被拿出来存在新的内存当中,地址同样会不一样,所以做出改变时不会相互影响;其它与浅copy一致,不可变数据类型改变时不会相互影响,且改变后地址会发生改变。