python中的深浅copy
1 对于python来说,一切变量都是对象,python中变量的存储,采用了引用语义,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。这样来存储的空间大小一致,因为变量只是保存了一个内存地址。
c语言使用的是值语义,把变量的值直接储存在变量的储存区中,这样就造成一个变量占用的内存可大可小
2 数据类型重新初始化和数据结构内部元素变化对python语义引用的影响
a 数据类型初始化:
str1='cap' print(id(str1)) str1='nihao' print(id(str1))
打印结果
47647576
48673936
在2次初始化str1的时候,str1指向的内存地址发生了改变
b 数据结构内部元素变化:
lst1=[1,2,3,4,5,6] print(id(lst1)) 打印结果34682952 lst1.append('yuan') print(id(lst1)) 打印结果34682952 lst1.pop() print((lst1)) print(id(lst1)) 打印结果34682952 lst1[0]='test' print(lst1) print(id(lst1)) 打印结果34682952 #重新给lst1赋值 lst1=[1,2,3,4] print(id(lst1)) 打印结果40539656
在上述的list的增删改中 lst1的内存地址并没有改变,但是在重新赋值的时候发生了变化
因此在python中数据结构是可以包含基础数据的。每个变量只是储存了值的引用(内存地址)
而每个数据结构内的元素也是只是储存了元素的内存地址
3 拷贝(浅拷贝和深拷贝)
对于复杂的数据结构来说,赋值就等于完全共享了资源,一个值的改变会完全被另一个值共享。
然而有的时候,我们偏偏需要将一份数据的原始内容保留一份,再去处理数据,这个时候使用赋值就不够明智了。
python为这种需求提供了copy模块。提供了两种主要的copy方法,一种是普通的copy,另一种是deepcopy。我们称前者是浅拷贝,后者为深拷贝。
copy是指在内存中完全是2块完全独立的内存空间,id值不一样 如果2个变量应用的是同一个对象地址,则能称之为copy
浅拷贝:
只拷贝一层,即将被拷贝对象中的内存地址引用过来
import copy lsta=['y6','y7','y8','y9','y10'] sourcelst=['y1','y2','y3','y4','y5',lsta] copy_lst=copy.copy(sourcelst) print(sourcelst) print(copy_lst) 结果: ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10']] ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10']]
sourcelst.append('y20') copy_lst.append('y21') print(sourcelst) print(copy_lst) 结果: ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10'], 'y20'] ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10'], 'y21']
sourcelst[0]='yx' print(sourcelst) print(copy_lst) 结果 ['yx', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10'], 'y20'] ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10'], 'y21']
lsta.append('test') print(sourcelst) print(copy_lst) 结果 ['yx', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10', 'test'], 'y20'] ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10', 'test'], 'y21']
sourcelst和copy_list只是储存的是变量的地址,所以当soucelst改变索引0的值的时候只是将'y1'的内存地址替换成'yx'的,但是copy_lst的索引0的值还是y1的内存地址
但是当修改了lsta的时候,souucels和copy_lst都回发生改变,因为它们两个存的都是lsta的内存地址
在copy复杂的数据类型的时候,要特别注意
深拷贝:
深拷贝,在内存中将所有的数据重新创建一份,并且拷贝到最后一层。这样两份数据就不会完全影响
lsta=['y6','y7','y8','y9','y10'] sourcelst=['y1','y2','y3','y4','y5',lsta] copy_lst=copy.deepcopy(sourcelst) print(sourcelst,id(sourcelst)) print(copy_lst,id(copy_lst)) 结果 ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10']] 41988680 ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10']] 41989960
sourcelst.append('source') copy_lst.append('copy') print(sourcelst,id(sourcelst)) print(copy_lst,id(copy_lst)) 结果 ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10'], 'source'] 41988680 ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10'], 'copy'] 41989960
lsta.append('lsta') print(sourcelst,id(sourcelst)) print(copy_lst,id(copy_lst)) 结果 ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10', 'lsta'], 'source'] 41988680 ['y1', 'y2', 'y3', 'y4', 'y5', ['y6', 'y7', 'y8', 'y9', 'y10'], 'copy'] 41989960
无论是直接改变source和copy的列表内元素,还是改变引用的可变数据类型来看,都不会对copy的数据造成影响
深拷贝在开辟内存空间的时候,遇到可变数据类型,就会在将可变数据类型中的数据内存地址全部复制下来,直到最后一层,保持原引用,所以原数据修改不会对copy的数据造成影响