Python深浅复制

首先来看一个例子

a = [1]
b = a
print(id(a),id(b)) #使用id函数查看一个变量在内存中的位置
1658278080904 1658278080904

可以看到a和b在内存中的位置是一样的,但是若a,b同时赋值python 内存数据拷贝_深浅复制,那么会出现不一样的情况,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

可以看到,使用深拷贝拷贝之后的数据完全是两个不同的数据,子对象也是完全不同的两个数据。数据完全不共享。