Python中值的引用深拷贝及浅拷贝
1 值的引用
赋值(=): 创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个
定义一个列表n,n1=n,如果此时改变n1的值,n的值也会改变,是因为这两个列表指向同一个内存空间,任何一个列表的改变都会对另一个造成影响
n=[1,4,6]
n1=n
n1.append(6)
print(n,id(n))
print(n1,id(n1))
输出:
[1, 4, 6, 6] 2357700937920
[1, 4, 6, 6] 2357700937920
n.pop()
print(n,id(n))
print(n1,id(n1))
输出:
[1, 4, 6] 1996662654976
[1, 4, 6] 1996662654976
2 深拷贝和浅拷贝的区别
深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用
- 浅拷贝:只是增加了一个指针指向已存在的内存地址
- 深拷贝:是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
(1)浅拷贝: 对另外一个变量的内存地址的拷贝,这两个变量指向同一个内存地址的变量值
- 公用一个值;
- 这两个变量的内存地址一样;
- 对其中一个变量的值改变,另外一个变量的值也会改变;
(2)深拷贝: 一个变量对另外一个变量的值拷贝。(copy.deepcopy())
- 两个变量的内存地址不同;
- 两个变量各有自己的值,且互不影响;
- 对其任意一个变量的值的改变不会影响另外一个;
2.1 浅拷贝
浅拷贝:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变
浅拷贝的两种方法:s.copy和s[:]都可以实现拷贝
(1)当列表中不含可变数据类型时,n1=n.copy(),此时n1和n的内容相同,但是这两个列表指定的内存地址空间不同
n=[1,4,6]
n1=n.copy()
print(n,id(n))
print(n1,id(n1))
输出:
[1, 4, 6] 1930278619328
[1, 4, 6] 1930278618368
- 此时改变其中一个列表对另一个列表没有影响
n.append(3) ##在列表n的末尾追加元素2
print(n,id(n))
print(n1,id(n1))
输出:
[1, 4, 6, 3] 2557658417216
[1, 4, 6] 2557658416256
(2)当列表中含可变数据类型时,n1=n.copy(),此时n1和n的内容相同,这两个列表指定的内存地址空间不同,对于列表中的变量[2,4]来说仅仅时内存地址的拷贝,n和n1的这个变量指向同一个内存地址的变量值,如果在其中一个列表修改这个变量,那么另一个列表中该变量也会随之改变
- 修改列表中非变量的值,只对修改的列表产生影响
n=[1,4,6,[2,4]]
n1=n.copy()
n.append(3)
print(n,id(n))
print(n1,id(n1))
输出:
[1, 4, 6, [2, 4], 3] 2144404063168
[1, 4, 6, [2, 4]] 2144404075008
- 修改列表中变量的值
n=[1,4,6,[2,4]]
n1=n.copy()
##n和n1指向的数据类型不同
print(n,id(n)) ## [1, 4, 6, [2, 4]] 1985455474048
print(n1,id(n1)) ## [1, 4, 6, [2, 4]] 1985455485888
## n和n1中的变量指向的内存地址相同
print(n[-1],id(n[-1])) ## [2, 4] 1985455475008
print(n1[-1],id(n1[-1])) ## [2, 4] 1985455475008
## 如果修改n中的变量,那么也会对n2中变量的修改,因为这两个列表中的变量指向的是同一个内存地址
n[-1].append(5)
print(n,id(n)) ## [1, 4, 6, [2, 4, 5]] 1985455474048
print(n1,id(n1)) ## [1, 4, 6, [2, 4, 5]] 1985455485888
print(n[-1],id(n[-1])) ## [2, 4, 5] 1985455475008
print(n1[-1],id(n1[-1])) ## [2, 4, 5] 1985455475008
## 如果修改n中的不可变数据类型,不会对n1产生影响,因为这两个列表的不可变数据类型指向的内存地址不同
n.append(3)
print(n,id(n)) ## [1, 4, 6, [2, 4, 5],3] 1985455474048
print(n1,id(n1)) ## [1, 4, 6, [2, 4, 5]] 1985455485888
2.2 深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
如果列表的元素包含可变数据类型, 一定要使用深拷贝
import copy
n=[1,4,6,[2,4]]
n1=copy.deepcopy(n)
print(n,id(n)) ## [1, 4, 6, [2, 4]] 2259448515072
print(n1,id(n1)) ## [1, 4, 6, [2, 4]] 2259448515328
## n和n1中的可变数据类型指向的内存地址不同,深拷贝时会将引用的对象拷贝到新的内存空间
print(n[-1],id(n[-1])) ## [2, 4] 2259448514240
print(n1[-1],id(n1[-1])) ##[2, 4] 2259448435456
# n中的可变数据类型修改时,n1不受改变
n[-1].append(5)
print(n,id(n)) ## [1, 4, 6, [2, 4, 5]] 2259448515072
print(n1,id(n1)) ##[1, 4, 6, [2, 4]] 2259448515328