Python中的浅复制和深复制
本文主要简析一下python中的列表的深浅复制和Numpy数组的深浅复制的特点和区别.
一.列表生成式
由于下文会使用到列表生成式,所以先来介绍一下列表生成式,可以让不太了解的同学熟悉一下.
使用列表生成式,可以将其它数据类型的数据特异(某一些数学运算)的转化为列表的形式.
下面是列表生成式的基本表达式:
[ (关于的表达式) for x in (可迭代对象a) 条件1,条件2,…]
注意:
- 上面的可迭代对象a可以是列表,元组,字典(遍历的是键),集合或字符串.
- 当上面表达式涉及数学运算时,可迭代对象a不可以是字符串,而且字典的键以及集合的元素均需为数值型.
# 例1.
a=[1,2,3,4,5]
[x**2 for x in a]
#输出结果为:
[1, 4, 9, 16, 25]
#例2.
a=[1,2,3,4,5]
[x**2 for x in a if x%2==0]
#输出结果为:
[4, 16]
二.python的可变数据类型和不可变数据类型
python中按修改值后内存地址的变化不同,可将数据划分为不可变数据类型和可变数据类型.
-
不可变数据类型: 当数据类型的对应变量的值发生改变后,它的内存地址也会发生改变. (不可变数据类型有整型(数值型),字符串,元组)
-
可变数据类型: 当数据类型的对应变量的值发生改变后,它的内存地址不发生改变. (可变数据类型有列表,字典,集合)
三.列表的深浅复制
1.引用: b=a
这种形式下列表a和b本质上是同一个东西,a和b的改变会互相影响
2.浅复制 (又称浅拷贝)
浅复制下,a和b的改变互不影响,列表a和b的内存地址不同,但它们对应元素的地址都一样 (俗称**‘新瓶装旧酒’**).
列表的浅复制有两种类型:
- b=a [:]
- b=a.copy()
以下是两种列表浅复制的实例结果,我们可以看到,a和b的改变互不影响,列表a和b的内存地址不同,但它们对应元素的地址都一样.大家有兴趣的话也可以自己设置列表验证一下.
3.深复制 (又称深拷贝)
from copy import deepcopy
b=deepcopy(a)
深复制下,a和b的改变互不影响,列表a和b的内存地址不同.
列表a和b中的不可变数据类型的元素的地址是一样的,因为数据类型不可变,所以只需要一个内存地址;列表a,b中的可变数据类型的元素的地址均都不一样.
以下是列表深复制的一个实例结果,我们可以看到,a和b的改变互不影响,列表a和b的内存地址不同.由于这个举例的列表中的元素我取的均是不可变数类型的元素(数值),所以a和b的元素的地址均一样.
如果列表有可变数据类型的元素的话,则a,b对应元素的地址将不同,大家可以自行验证.
四.Numpy数组的深浅复制
1.完全不复制(引用): b=a
这里和列表的一样,a和b本质上为同一个东西,改变互相影响.
2.完全复制(副本): b=a.copy()
这里也称深复制,列表a和b改变互不影响,它们对应元素的地址均一样,不分数据类型.
下面是在数组元素里插入了一个字典,可以看到它在a,b中的地址都是一样的.
3.浅复制(视图): b=a.view()
这里的浅复制又称视图,意思是a,b都是指向同样的东西,只是从不同的方向指向.a,b的维度改变不会互相影响,但是a,b里的元素改变会互相改变.
a,b对应元素的地址均一样,不分数据类型.
下面是在数组元素里插入了一个集合,可以看到它在a,b中的地址都是一样的.
4. 延伸
-
Numpy数组切片时就是一个浅复制,返回的是一个视图,当我们对这个视图进行修改时,原数据也会改变.所以当我们要处理的数据量很大时,可以用这个方法修改局部数据.(在列表中,切片返回的是副本或称深浅复制的某一种, 没有考究过)
-
数组.reshape() 也是一个浅复制