前言
由于Python 存储变量的方法跟其他OOP语言不同,所以在使用Python赋值的时候要特别注意!!我就被坑过一次做的实验写的程序就是因为深浅拷贝问题错了,差点造成写的论文挂掉!!非常之可恨。一直想写篇博客一直没动手,直到最近又碰到了这个问题所以做个总结。写程序的时候特别注意!!!
深浅拷贝的概念
我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。而浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。这就和我们寻常意义上的复制有所不同了。
Python中直接赋值、浅拷贝和深度拷贝的概念
- 直接赋值:其实就是对象的引用(别名)这是个浅拷贝!!!
- 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象
- 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象
拷贝实例
# 浅拷贝实例
a = {1: [1,2,3]}
b = a.copy()
a, b
({1: [1, 2, 3]}, {1: [1, 2, 3]})
a[1].append(4)
a, b
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
# 深度拷贝需要引入 copy 模块
import copy
c = copy.deepcopy(a)
a, c
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
a[1].append(5)
a, c
({1: [1, 2, 3, 4, 5]}, {1: [1, 2, 3, 4]})
特殊概念“可变对象”
1.浅拷贝"="的使用
#1.使用=复制不可变对象的值,以及复制以后修改其值后的变化。
val1 = 1000
val2 = val1
print("val1 is :{0},val2 is :{1}".format(val1,val2))#val1 is :1000,val2 is :1000
print(id(val1),id(val2)) #34052192 34052192
#这时候修改val1的值,尽管val2指向val1.但因为val1是不可变类型,修改其值,会重新给新值分配内存,然后指向他。
val1 += 1
print(val1,id(val1),val2,id(val2)) #1001 10131616 1000 10131568 值不一样,内存地址也不一样了
#1.使用=复制可变对象的值,以及复制以后修改其值后的变化。
ls1 =[1,2,3,4]
ls2 = ls1
print(id(ls1),id(ls2)) #43702792 43702792 直接使用=复制变量,内存地址一样,值也一样。
print(ls1,ls2) #[1, 2, 3, 4] [1, 2, 3, 4]直接使用=复制变量,内存地址一样,值也一样。
#这时候修改可变对的值,因为其值可变,所以只需要在原内存地址上修改即可。
ls1.append(5)
print(id(ls1),id(ls2)) #可变对象修改其值,内存引用不变
print(ls1,ls2) #[1, 2, 3, 4, 5] [1, 2, 3, 4, 5] 因为两个变量的内存指向一样,所以值也一样。
2.深拷贝:copy.deepcopy()函数
#1.使用copy.deepcopy()拷贝不可变对象的值,以及复制以后修改其值后的变化。
val1 = 1000
val2 = copy.deepcopy(val1)
print("val1 is :{0},val2 is :{1}".format(val1,val2))#val1 is :1000,val2 is :1000
print(id(val1),id(val2)) #33717408 33717408 对于不可变对象,深度拷贝内存地址没有修改。
val1 += 1
print(val1,id(val1),val2,id(val2)) #1001 33717904 1000 33717408
#1.使用copy.deepcopy()复制可变对象的值,以及复制以后修改其值后的变化。
ls1 =[1,2,3,4]
ls2 = copy.deepcopy(ls1)
print(id(ls1),id(ls2)) #34628472 34628712 注意对于可变对象深度拷贝后内存地址都修改了。
print(ls1,ls2) #[1, 2, 3, 4] [1, 2, 3, 4]
ls1.append(5)
print(id(ls1),id(ls2)) #34628472 34628712
print(ls1,ls2) #[1, 2, 3, 4, 5] [1, 2, 3, 4] #注意这个时候ls2的值没有随着ls1修改。
总结:其实对于浅拷贝和深拷贝来说,如果拷贝对象都是不可变对象的话,那么两者效果是一样的。如果是可变对象的话,“=”拷贝的方式,只是拷贝了内存中的地址引用,两个对象的地址引用一样,所以两个对象的值会随着一方的修改而修改。而对于deepcopy()来说,如果是可变对象的话,那么拷贝内容后新对象的内存地址也会重新分配,跟原来的内存地址不一样了。所以两者任意修改变量的内容不会对另一方造成影响。
3.注意一个特殊的copy(),跟深浅拷贝都有区别,慎用。
1、copy.copy对于可变类型,会进行浅拷贝
2、copy.copy对于不可变类型,不会拷贝,仅仅是指向
1.使用copy()拷贝不可变对象
val1 = 1000
val2 = copy.copy(val1)
print(val1,val2)##1000 1000
print(id(val1),id(val2))#8551568 8551568
2.使用copy()拷贝可变对象
ls1 =[1,2,3,4]
ls2 = copy.copy(ls1)
ls1.append(5)
print(ls1,ls2) #[1, 2, 3, 4, 5] [1, 2, 3, 4]
看上去copy()函数效果和deepcopy()效果一样,可变对象拷贝后值也没有随着一个对象的修改而修改。
然后真实情况真是这样嘛?请看下面的案例,同样是拷贝可变对象。
origin = [1, 2, [3, 4]]
cop1 = copy.copy(origin)
cop2 = copy.deepcopy(origin)
origin[2][0] = "hey!" #修改数据源的值
print(cop1,cop2) #[1, 2, ['hey!', 4]] [1, 2, [3, 4]]
很显然这时copy()函数拷贝的值随着原对象的值修改了,而deepcopy()的值没有随着原对象的值修改。
主要是因为deepcopy会将复杂对象的每一层复制一个单独的个体出来对于copy()函数要慎用,慎用。
参考文献
[1]Python中copy,deepcopy,=之深拷贝浅拷贝使用详解
[2]python中copy()和deepcopy()详解
[3]Python 字典(Dictionary) copy()方法
[4]Python 直接赋值、浅拷贝和深度拷贝解析
本文详细解析了Python中深拷贝与浅拷贝的区别,通过实例演示了直接赋值、浅拷贝(copy)和深拷贝(deepcopy)的不同行为,并强调了可变对象在拷贝过程中的注意事项。
2536

被折叠的 条评论
为什么被折叠?



