深拷贝与浅拷贝

#原创,转载请先留言联系

在阅读此文前,建议先看一下我的另一篇博文:https://www.cnblogs.com/chichung/p/9607226.html

浅拷贝

import copy
copy.copy(obj)

深拷贝

import copy
copy.deepcopy(obj)
  • 深拷贝与浅拷贝的区别

1.浅拷贝

import copy

a = [1,2]
b = [3,4]
c = [a,b]
d = copy.copy(c)
print('c的内存地址',id(c))
print('d的内存地址',id(d))

print('
c[0]的内存地址',id(c[0]))
print('d[0]的内存地址',id(d[0]))
print('a的内存地址',id(a))

输出:
c的内存地址 139752474494984
d的内存地址 139752475133128

c[0]的内存地址 139752474562824
d[0]的内存地址 139752474562824
a的内存地址 139752474562824

由输出结果可知。d列表浅拷贝了c列表,所以d列表重新分配了一个内存空间。但是,由于是浅拷贝,d列表的内部,a列表与b列表并没有进行拷贝,也就没有分配新的内存空间,还是原来的内存空间地址。所以说,浅拷贝是对象的最外层的拷贝

2.深拷贝

import copy

a = [1,2]
b = [3,4]
c = [a,b]
d = copy.deepcopy(c)
print('c的内存地址',id(c))
print('d的内存地址',id(d))

print('
c[0]的内存地址',id(c[0]))
print('d[0]的内存地址',id(d[0]))
print('a的内存地址',id(a))

输出:
c的内存地址 139657913055240
d的内存地址 139657913118792

c[0]的内存地址 139657913118984
d[0]的内存地址 139657913118920
a的内存地址 139657913118984

由输出结果可知。d列表深拷贝了c列表,所以d列表重新分配了一个内存空间。但是,由于是深拷贝,d列表的内部,a列表与b列表也进行了拷贝,也重新分配了内存空间。所以说,深拷贝是拷贝是对象的所有层的拷贝。

上面针对的是可变类型数据的深浅拷贝,不可变类型的深浅拷贝又是不一样的。

附:

不可变类型(不可变类型不能对其内容直接修改,修改的话其实是将新的数据储存到新的内存中):数字、字符串、元组、不可变集合

可变类型(可变类型可以对其内容直接修改,修改的话也是将新的数据储存到原来的内存中):列表、字典、可变集合

  • 不可变类型的深浅拷贝(元组,字符串,数字)
import copy

a = (1,2)
b = copy.copy(a)
c = copy.deepcopy(a)

print('a的内存空间为',id(a))
print('浅拷贝b的内存空间为',id(b))
print('深拷贝c的内存空间为',id(c))

输出:
a的内存空间为 140239461449608
浅拷贝b的内存空间为 140239461449608
深拷贝c的内存空间为 140239461449608

由输出结果可知。a的元组,b对a进行了浅拷贝,但是内存空间还是没有改变!c对a进行了深拷贝,内存空间还是没有变!可知,对于不可变类型,浅拷贝与深拷贝都是相同的 ,都不会单独开辟内存空间,而是引用原来的内存空间。

  • 可变类型与不可变类型嵌套的深浅拷贝
import copy

b = [1,2]
a= (b, )
copy_a = copy.copy(a)
deepcopy_a = copy.deepcopy(a)

print('a的内存空间为',id(a))
print('浅拷贝后copy_a的内存空间为',id(copy_a))
print('深拷贝后deepcopy_a的内存空间为',id(deepcopy_a))

print('
a[0]的内存空间为',id(a[0]))
print('浅拷贝后copy_a[0]的内存空间为',id(copy_a[0]))
print('深拷贝后deepcopy_a[0]的内存空间为',id(deepcopy_a[0]))

输出:
a的内存空间为 140588590524736
浅拷贝后copy_a的内存空间为 140588590524736
深拷贝后deepcopy_a的内存空间为 140588560914976

a[0]的内存空间为 140588560399496
浅拷贝后copy_a[0]的内存空间为 140588560399496
深拷贝后deepcopy_a[0]的内存空间为 140588560398408

要拷贝的是a,a是元组里面嵌套一个字典,a=([1,2],)

当进行浅拷贝时,只拷贝最外层,因为最外层是元组,是不可变类型,所以只是引用原来的内存空间,内存与a相同。

当进行深拷贝是,先拷贝最外层,因为最外层是元组,是不可变类型,只是引用原来的内存空间。但是当他开始拷贝第二层时,发现是个可变类型,然后就分配一个新的空间,因此,深拷贝后deepcopy_a[0]的内存空间a[0]的内存空间不一样。但是问题来了,为什么拷贝后deepcopy_a的内存空间a的内存空间不一样?图解!

明白了吧?如果是嵌套可变类型和不可变类型的,实质上深拷贝还是把全部层都拷贝了一遍,全部层都分配了新的内存空间。

还有嵌套全是不可变类型的,那深浅拷贝都是引用原来的内存地址,并不会拷贝。

还有嵌套全是可变类型的,那浅拷贝就会给最外层分配新的内存地址,其它层内存地址不变。深拷贝就会给拷贝所有层,给所有层分配新的内存地址。

相信你搞得懂上面的示例,这两个肯定都懂的。这里就不演示了。

  • 列表切片、字典中的copy都采用的是浅拷贝

1.列表切片

import copy

a = [[1,2],[3,4]]
b = a[:]

print('a的内存空间',id(a))
print('b的内存空间',id(b))

print('
a[0]的内存空间',id(a[0]))
print('b[0]的内存空间',id(b[0]))

输出:
a的内存空间 140020984498184  # 最外层拷贝了,因为内存空间重新分配了
b的内存空间 140020984565832

a[0]的内存空间 140020984566024  # 里面的层没有拷贝,还是原来的内存空间
b[0]的内存空间 140020984566024
import copy

a = {'name':['chichung','cong'],'age':22}
b = a.copy()

print('字典a的内存地址:',id(a))
print('字典b的内存地址:',id(b))

print('
字典a里name的内存地址:',id(a['name']))
print('字典b里name的内存地址:',id(b['name']))

输出:
字典a的内存地址: 139921205047240  # 最外层拷贝了,因为内存空间重新分配了
字典b的内存地址: 139921205006472

字典a里name的内存地址: 139921174875464  # 里面的层没有拷贝,还是原来的内存空间
字典b里name的内存地址: 139921174875464

因此,列表切片、字典中的copy都采用的是浅拷贝。

最后的tips:python中内存数据的拷贝默认是浅拷贝。

原文地址:https://www.cnblogs.com/chichung/p/9609786.html