温馨提醒:本文默认使用3.X版本的Python
V1.1,修复图片数字错误。
一、什么是深浅拷贝?
拷贝,即复制!深浅则是根据复制的层次来区分!如浅拷贝只能将内存地址第一层地址拷贝,而深拷贝可将所有层次地址拷贝!需要注意的是,变量间接引用不叫拷贝列表,比如:
list2 = [1,2,3]
list3 = list2
#这个就是变量间接引用而已,内存地址都没变!
二、为什么要有深浅拷贝?
我们经常需要引用变量,Python为了节约内存空间与提升性能,经常会有变量重复被使用;但有时会需要改动其中一些地方,又不期望影响到别处引用的原值,这时候就有了深浅拷贝!
三、如何使用?
先来一个要求:
1、拷贝源列表产生新列表
2、二者完全独立(即内存地址不一样)
3.1、浅拷贝
使用copy()可完全拷贝一份列表且二者内存地址相互独立,意味着新复制的是在内存中新开辟了新的空间!
>>> list1 = ["hello","hi",[2,8]]
>>> list2 = list1.copy()
>>> print(list1,list2)
['hello', 'hi', [2, 8]] ['hello', 'hi', [2, 8]]
>>> print(id(list1),id(list2))
59791368 59934760
但是列表里存的地址信息指向同样的内存空间,列表元素ID是一样的,只是列表名不一样。看数据类型是否可变,改的是可变类型。老油条如Python,能偷懒绝不动手!
>>> print(id(list1[2][1]),id(list2[2][1]))
2042951712 2042951712
###### 3.1.1、浅拷贝即将原列表第一层内存地址不加区分完全拷贝给新列表,适用不可变类型;对于可变类型,我们可以将可变类型中包含的值改变,但内存地址不变,即源列表的索引指向仍然指向原来的内存地址,于是新列表也跟着一起受影响,如下
>>> list1[2][1]=3
>>> print(list1[2],list2[2])
[2, 3] [2, 3]
3.2、图解内存地址与空间
3.3、深拷贝
如上浅拷贝所演示,我们要想copy得到的新列表与源列表的改操作完全独立开来,需要一种可以区分可变类型与不可变类型的copy机制,这就是深拷贝了!
使用方法如下所示:
import copy
list1=["hello","hi",[2,8]]
list2=copy.deepcopy(list1)
来看一下ID
>>> print(id(list1),id(list2))
16586312 59934792
跟浅拷贝一样改一个元素,这次list1改变不会影响到list2了!
>>> list1[2][1]=3
>>> print(list1,list2)
['hello', 'hi', [2, 3]] ['hello', 'hi', [2, 8]]
再来看看子列表ID
#可以看到相比浅拷贝,这里内存地址已经变了!
>>> print(id(list1[2]),id(list2[2]))
59935176 16586504
真相真的是这样吗?Python这么老奸巨猾!
#老奸巨猾如Python,只有改了的才会新开辟内存空间,一样的值还是共享使用内存空间!一切都是为了性能优化!
>>> print(id(list1[2][0]),id(list2[2][0]))
2042951616 2042951616
>>> print(id(list1[2][1]),id(list2[2][1]))
2042951632 2042951712
3.3.1、小结:
深拷贝,针对不可变类型,用的还是原来的地址;可变类型则是新瓶装旧酒产生了新内存地址存入相同内容,一切都是为了效能优化!