4、Python深浅拷贝基础

Python入门 / 2020-09-01

温馨提醒:本文默认使用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、小结:

深拷贝,针对不可变类型,用的还是原来的地址;可变类型则是新瓶装旧酒产生了新内存地址存入相同内容,一切都是为了效能优化!

世间微尘里 独爱茶酒中