day2-深浅拷贝
简述
在说深浅拷贝之前,首先先来说一下,Python的数据结构
Python的数据结构总体分为两类:一类:字符串和数字,另外一类:列表、元组、字典等
1.字符串和数字
说明:赋值(=)、浅拷贝(copy)和深拷贝(deepcopy)其实都毫无意义,因为它们永远指向同一个内存地址
>>> import copy >>> name="huwei" >>> print(id(name)) #打印name的内存地址 69064672 #赋值 >>> name1=name >>> print(id(name1)) 69064672 #浅拷贝 >>> name2=copy.copy(name) >>> print(id(name2)) 69064672 #深拷贝 >>> name3=copy.deepcopy(name) >>> print(id(name3)) 69064672
如图所示:
2、列表、元组、字典(以及其他)
说明:对于列表、元组和字典,浅拷贝(copy)、深拷贝(deepcopy)而言,其内存地址是不同的。
2.1赋值(=)
说明:赋值只是创建一个变量,该变量指向原来的内存地址,只是对相同对象的引用。
>>> name1 = ["a","b","c",["m","n"],"e"] >>> name2 = name1 >>> print(id(name1),id(name2)) 71524880 71524880 #两个变量的地址是相同的
如图所示:
2.2浅拷贝(copy)
说明:浅拷贝是指在内存地址中,各自产生独立的对象(内存地址),但是他们的子对象还是指向统一对象(列表、元组和字典中的copy()方法都是浅拷贝)
>>> import copy >>> name1 ['a', 'b', 'c', ['m', 'n'], 'e'] #浅copy >>> name2=copy.copy(name1) >>> print(name1,",",id(name1)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 71524880 >>> print(name2,",",id(name2)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 71310752 #修改列表中的元素 >>> name1[0]="x" >>> name1[3][0]="y" >>> print(name1,",",id(name1)) ['x', 'b', 'c', ['y', 'n'], 'e'] , 71524880 >>> print(name2,",",id(name2)) ['a', 'b', 'c', ['y', 'n'], 'e'] , 71310752
如图所示:
解析:因为浅拷贝只拷贝了第一层,所以拷贝的变量和被拷贝的变量的第二层的列表的内存地址是一样的。
>>> import copy >>> name1=['a', 'b', 'c', ['m', 'n'], 'e'] >>> name2=copy.copy(name1) >>> print(name1,",",id(name1)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 71524880 >>> print(name2,",",id(name2)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 71310752 >>> name1[0]="x" >>> name1[3][0]="y" #name1[3][0]的内存地址和name2[3][0]的内存地址是一样的 >>> print(name1,",",id(name1),id(name1[3][0])) ['x', 'b', 'c', ['y', 'n'], 'e'] , 64626600 16031072 >>> print(name2,",",id(name2),id(name2[3][0])) ['a', 'b', 'c', ['y', 'n'], 'e'] , 64598704 16031072
注意:浅拷贝的三种表现形式
1.用copy模块中的copy方法(如上)
2.用切片的方式:
>>> name1=['a', 'b', 'c', ['m', 'n'], 'e'] >>> name2=name1[:] >>> name2 ['a', 'b', 'c', ['m', 'n'], 'e'] >>> print(name1,",",id(name1)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 64626600 >>> print(name2,",",id(name2)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 64667560
3.用列表自带的方法:
name1=['a', 'b', 'c', ['m', 'n'], 'e'] name2=name1.copy() print(name1,id(name1)) ['a', 'b', 'c', ['m', 'n'], 'e'] 69795192 print(name2,id(name2)) ['a', 'b', 'c', ['m', 'n'], 'e'] 69844784
3.1深拷贝(deepcopy)
说明:完全拷贝了父对象及其子对象,两者完全是独立的,也就是说将所有的数据重新创建一份。
>>> import copy >>> name1=['a', 'b', 'c', ['m', 'n'], 'e'] #深拷贝 >>> name2=copy.deepcopy(name1) >>> print(name1,",",id(name1)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 58428832 >>> print(name2,",",id(name2)) ['a', 'b', 'c', ['m', 'n'], 'e'] , 58541920 >>> name1[0]="x" >>> name2[3][0]="y" >>> print(name1,",",id(name1),id(name1[0])) ['x', 'b', 'c', ['m', 'n'], 'e'] , 58428832 14771904 >>> print(name2,",",id(name2),id(name2[3][0])) ['a', 'b', 'c', ['y', 'n'], 'e'] , 58541920 14982496
如图所示:
解析:因为深拷贝会拷贝到最后一层的内存地址,所以最后一层的内存地址是不同的。
总结
建议:在内存足够的情况下,选择深拷贝,这样逻辑处理独立,不会产生上下文的影响,不容易发生难以解决的bug。