Python深浅复制
首先来看一个例子
a = [1]
b = a
print(id(a),id(b)) #使用id函数查看一个变量在内存中的位置
1658278080904 1658278080904
可以看到a和b在内存中的位置是一样的,但是若a,b同时赋值,那么会出现不一样的情况,a,b在内存中的位置不同
a = [1]
b = [1]
print(id(a),id(b))
1658277133832 1658277369160
显然,a,b在内存中的位置是不一样的,这就涉及到了深浅复制。
在Python中,将同一列表赋值给不同的变量,做的就是浅复制,(即复制了最外层容器,副本中的元素是源容器中元素的引用)。如果所有元素都是不可变的,那么这样没有问题,还能节省内存。但是,如果有可变的元素,可能就会导致意想不到的问题。
在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用
(1)赋值:数据完全共享,是同一对象
a = [1,2,3,[1,2,3]]
b = a
a[0] = 8
print(a,b)
print(a is b) #使用is函数查看是否是同一对象
[8, 2, 3, [1, 2, 3]] [8, 2, 3, [1, 2, 3]]
True
(2)copy浅拷贝,没有拷贝子对象,所以原始数据改变,子对象不会改变
浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)
浅拷贝可以使用列表的copy方法,也可以导入copy模块,使用copy模块中的copy
下面是使用列表的list方法
a = [1,2,3]
b = a.copy()
a[0] = 8
print(a,b,a is b)
[8, 2, 3] [1, 2, 3] False
下面是使用copy模块的copy
import copy
a = [1,2,3]
b = copy.copy(a)
a[0] = 8
print(a,b,a is b)
[8, 2, 3] [1, 2, 3] False
当列表中有子对象即列表中嵌套列表时,浅拷贝只拷贝了最外边那一层的列表,修改子对象数据时,拷贝过来的数据也会被修改,而修改第一层列表时修改原始数据,拷贝得到的数据并不会被修改,这就是数据半共享。
import copy
a = [1,2,3,[1,2,3]]
b = copy.copy(a)
a[0] = 8
a[3][0] = 8
print(a)
print(b)
print(a is b)
print(a[0] is b[0])
print(a[3] is b[3])
[8, 2, 3, [8, 2, 3]]
[1, 2, 3, [8, 2, 3]]
False
False
True
可以看到,包含子对象的列表,浅拷贝后两个变量并不是同一个数据,但是子对象在拷贝后是同一个数据,修改原始数据和拷贝后子对象的值,另外一个子对象的值也会被修改。因为子对象实际上仍然是引用。
(3)深拷贝,包含对象里面的子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)
深拷贝,使用copy模块中的deepcopy
import copy
a = [1,2,3,[1,2,3]]
b = copy.deepcopy(a)
a[3][0] = 8
print(a)
print(b)
print(a is b)
print(a[3] is b[3])
[1, 2, 3, [8, 2, 3]]
[1, 2, 3, [1, 2, 3]]
False
False
可以看到,使用深拷贝拷贝之后的数据完全是两个不同的数据,子对象也是完全不同的两个数据。数据完全不共享。