Python—浅拷贝和深拷贝的详解
首先我们要了解一下浅拷贝和深拷贝的概念:
1.浅拷贝
定义:浅拷贝是对另外一个变量的内存地址的拷贝,这两个变量指向同一个内存地址的变量值。
注:仅仅拷贝的是目标变量的所在地址,目标变量的所在地址不发生任何变化。
实际上,变量中并没有存储任何的值,它只是指向了一个内存地址,而这个地址里存储着具体的内容,例如把变量a赋值给变量b的时候,实际上是把a指向内存中某对象的链接赋给了b,也就是说,现在a和b都指向了同一个对象。因此,在改变了内存中array的值后,而a与b都引用了该array对象,所以都一起发生了变化
浅拷贝的特点:
- 公用一个值;
- 这两个变量的内存地址一样;
- 对其中一个变量的值改变,另外一个变量的值也会改变;
2.深拷贝
定义:一个变量对另外一个变量的值拷贝。
注:拷贝的是目标变量的值,是真实的拷贝,新的变量产生了新的内存地址。
深拷贝的特点:
- 变量的内存地址不同;
- 变量各有自己的值,且互不影响;
- 对其任意一个变量的值的改变不会影响其余变量的值;
3. Python中表(List)数据中
-
直接赋值给另一个变量是 浅拷贝
-
切片操作 是 深拷贝
#Python中的浅拷贝 a = [1,2,3,4,5,6] b = a #a直接赋值b print('a的初始内存地址:',id(a)) print('b的初始内存地址:',id(b)) b.append(7)#对b尾部加数字7 print('a:',a) print('b:',b) print('a的当前内存地址:',id(a)) print('b的当前内存地址:',id(b)) print('-----------------------------') c = a[0:3] # c使用切片进行拷贝 c.append(8)#在c的尾部添加数字8 a.append(9) print('a:',a) print('b:',b) print('c:',c) print('a的内存地址:',id(a)) print('b的内存地址:',id(b)) print('c的内存地址:',id(c))#打印c的内存地址 """ a的初始内存地址: 2186126011016 b的初始内存地址: 2186126011016 a: [1, 2, 3, 4, 5, 6, 7] b: [1, 2, 3, 4, 5, 6, 7] a的当前内存地址: 2186126011016 b的当前内存地址: 2186126011016 ----------------------------- a: [1, 2, 3, 4, 5, 6, 7, 9] b: [1, 2, 3, 4, 5, 6, 7, 9] c: [1, 2, 3, 8] a的内存地址: 2186126011016 b的内存地址: 2186126011016 c的内存地址: 2186126011976 """
-
显然浅拷贝后变量的存放地址相同,仅仅是拷贝到内存地址,且其中一个变量发生增删等操作会直接改变目标变量的值;
-
深拷贝后变量的存放地址不同,说明另外开辟了新的内存空间存放拷贝后的变量,且其中一个变量的增删操作不会不会对其余的变量产生影响。
4. Numpy 中的深拷贝和浅拷贝
np.copy()
方法是 深拷贝;- 切片操作是特殊的 浅拷贝;(注意与python的list切片使用是深拷贝,这是一种特殊的浅拷贝,因为出现了新的内存地址,但是数据修改仍会同步)
- 直接赋值给另一个变量是 浅拷贝。
# 导入numpy
import numpy as np
a = np.arange(6)
print('一、浅拷贝')
#1、直接赋值法
b = a
#2、切片法
c = a[:]
print('a:',a)
print('b:',b)
print('c:',c)
print('改变b的第1个位置上的元素之后———')
# 改变a中第一个元素的值
a[0] = 4
c[2] = 7
print('a:',a,id(a))
print('b:',b,id(b))
print('c:',c,id(c))
print('二、深拷贝')
d = a.copy()
print('a:',a)
print('d:',d)
# 将a的第2个元素值也更改
a[1] = 5
print('赋值后:')
print('a:',a,id(a))
print('d:',d,id(d))
"""
一、浅拷贝
a: [0 1 2 3 4 5]
b: [0 1 2 3 4 5]
c: [0 1 2 3 4 5]
改变b的第1个位置上的元素之后———
a: [4 1 7 3 4 5] 2186126040480
b: [4 1 7 3 4 5] 2186126040480
c: [4 1 7 3 4 5] 2186126040960 #numpy中的切片的使用比较特殊,会发现存储地址已经发出变化,但是a和c之间仍然会相互影响,所以这是一种特殊的浅拷贝。
二、深拷贝
a: [4 1 7 3 4 5]
d: [4 1 7 3 4 5]
赋值后:
a: [4 5 7 3 4 5] 2186126040480
d: [4 1 7 3 4 5] 2186125987392
"""