python深拷贝浅拷贝,python中的深拷贝和浅拷贝

  python深拷贝浅拷贝,python中的深拷贝和浅拷贝

  仅供参考,转载请注明出处。

  深抄,浅抄1。灯光副本灯光副本是对象的顶层副本。

  通俗的理解就是:抄引用,不抄内容。

  浅抄示意图

  用ipython3写几个例子看看:

  在[1]中:a=[1,2,3,4]

  在[2]中:b=a

  在[3]中

  输出[3]: [1,2,3,4]

  在[4]: b

  输出[4]: [1,2,3,4]

  In [5]: id(a) #检查变量a的内存地址。

  Out[5]: 140490275823112

  In [6]: id(b) #检查变量b的内存地址。

  Out[6]: 140490275823112

  在[7]:导入副本

  在[8]中:

  in[8]:c=copy . copy(a)# copy a with copy

  在[9]中:c

  输出[9]: [1,2,3,4]

  In [10]: id(c) #检查变量c的内存地址。

  Out[10]: 140490271207112

  在[11]中:从上面的例子来看,在b=a和c=copy.copy(a)两种方式中,b和a的内存地址是14049027582312,而c的内存地址是140490271207112。c已经指向了另一个内存地址。

  解释:b=a符合光抄法则。

  思考:既然浅拷贝都指向同一个内存地址,那么如果修改一个变量,那么另一个变量指向的所有值会一起修改吗?

  #首先,在最后一步之后检查三个变量a b c的值。

  在[11]: c

  输出[11]: [1,2,3,4]

  在[12]中

  Out[12]: [1,2,3,4]

  在[13]: b

  输出[13]: [1,2,3,4]

  #因为A和B的两个变量都指向同一个内存地址,所以在B的列表中添加一个5,并检查变量的修改。

  在[14]中:b .追加(5)

  在[15]: b

  Out[15]: [1,2,3,4,5]

  在[16]中

  Out[16]: [1,2,3,4,5]

  在[17]: c

  Out[17]: [1,2,3,4]

  #从上面三个变量可以看出,变量A和B是同时被修改的,而C因为内存地址不同,所以没有被修改。

  #然后修改变量C,在列表中添加一个数字6。当然不会影响变量A和b,实践看看。

  在[18]中:c .追加(6)

  在[19]: c

  Out[19]: [1,2,3,4,6]

  在[20]中

  Out[20]: [1,2,3,4,5]

  在[21]: b

  Out[21]: [1,2,3,4,5]

  在[22]中:

  注:其实上面的理解对于轻抄是有一定偏差的。虽然b=a确实是一种轻拷贝,但是轻拷贝c=copy.copy(a)是另一种轻拷贝。那么为什么记忆不一样呢?

  其实浅拷贝只是拷贝最顶层的数据,还会生成一个新的变量,此时内存会有所不同。这里有另一个例子来说明:

  在[22]中:d=[a,b] #先设置变量D将A和b相加。

  在[23]中:e=copy.copy(d) #用e轻拷贝d,此时会生成一个新的内存变量e。

  在[24]中:id(d) #检查d的变量存储器

  Out[24]: 140490271478024

  在[25]: id(e) #查E的变量内存,确实和d不一样,但是E复制的A和B的地址呢?

  Out[25]: 140490295815880

  In [26]: id(d[0]) #首先检查变量A在d中的列表地址。

  Out[26]: 140490275823112

  In [27]: id(e[0]) #看E中变量A的列表内存地址,其实是一样的。

  Out[27]: 140490275823112

  在[28]: id(d[1])

  Out[28]: 140490275823112

  在[29]: id(e[1])

  Out[29]: 140490275823112

  在[30]中:从上面的结果来看,C和D的变量内存地址是不同的,但是A和B在C和D中的内存地址是相同的。

  那么是不是A修改了,那么C和D也会同时修改呢?

  在[30]中:a .附加(7)

  在[31]中

  Out[31]: [1,2,3,4,5,7]

  在[32]: b

  Out[32]: [1,2,3,4,5,7]

  在[33]: e[0]

  Out[33]: [1,2,3,4,5,7]

  在[34]: d[0]

  Out[34]: [1,2,3,4,5,7]

  在[35]:答案会同时修改,因为内存地址都是一致的。

  下面是一个理解图:

  2.深层拷贝

  深层副本是对象所有级别的副本(递归)。

  在[35]中:a=[11,22]

  In [36]: b=copy.deepcopy(a) #深度复制a指向的列表。

  在[37]中

  出[37]: [11,22]

  在[38]: b

  出[38]: [11,22]

  在[39]: id(a) #检查a的存储器地址。

  Out[39]: 140490295123912

  在[40]: id(b) #看B的内存地址,可以看到它和变量a不一致。

  Out[40]: 140490295270088

  在[43]中:a.append(33) #那么给A加一个变量33肯定不会影响b .执行一下看看。

  在[44]中

  Out[44]: [11,22,33]

  在[45]中

  出[45]: [11,22]

  在[46]:但是从这个例子来看,深度复制并没有什么特别之处。

  进一步了解深度复制

  从前面浅拷贝的例子,我们来看看使用深拷贝时有什么变化。

  在[46]中:a=[1,2,3,4]

  在[47]中:b=a

  在[48]中:d=[a,b]

  在[49]中:e=copy.deepcopy(d) #用e对d进行深度复制,然后d中的所有变量将被深度递归。

  在[50]中:id(d) #检查变量d的内存。

  Out[50]: 140490296753416

  在[51]: id(e) #看变量E的内存,可以看到E和D的内存地址是不一样的。

  Out[51]: 140490295210696

  #上例中,d[0]的内存地址和c[0]的是一样的,但是这里的深度复制是不一样的。

  在[52]: id(d[0])

  Out[52]: 140490271451720

  在[53]: id(e[0])

  Out[53]: 140490294520008

  在[54]中:id(e[1])

  Out[54]: 140490294520008

  在[55]: id(d[1])

  Out[55]: 140490271451720

  #从上面的打印来看,深度拷贝后,E和D的所有内存变量都不一样了。

  在[56]中:d

  Out[56]: [[1,2,3,4],[1,2,3,4]]

  在[57]: e

  Out[57]: [[1,2,3,4],[1,2,3,4]]

  在[58]中:a .追加(5)

  在[59]: d

  Out[59]: [[1,2,3,4,5],[1,2,3,4,5]]

  在[60]: e

  Out[60]: [[1,2,3,4],[1,2,3,4]]

  在[61]:3。其他复制方式

  分段表达式d=c[:]可以赋值一个序列。

  在[1]中:a=[11,22]

  在[2]中:b=[33,44]

  在[3]中:c=[a,b]

  在[4]: d=c[:] #分段表达式中

  在[5]中:c

  Out[5]: [[11,22],[33,44]]

  在[6]: d

  Out[6]: [[11,22],[33,44]]

  #使用切片表达式传递值后查看变量内存,可以看出C和D是不同的。

  在[7]中:id(c)

  Out[7]: 140089352809416

  在[8]中:id(d)

  Out[8]: 140089352792904

  #然后再看c[0]和d[0]的内存变量。从结果来看,是一样的。

  In [9]: id(c[0])

  Out[9]: 140089352742024

  在[10]: id(d[0])

  Out[10]: 140089352742024

  #所以既然内存地址都是一样的,那就给A加一个变量33,看看值是不是同时被修改了。

  在[11]中

  Out[11]: [11,22]

  在[12]中:a .追加(33)

  在[13]中

  Out[13]: [11,22,33]

  在[14]: c

  Out[14]: [[11,22,33],[33,44]]

  在[15]: d

  Out[15]: [[11,22,33],[33,44]]

  在[16]:从上面的结果来看,切片表达式是一种浅拷贝。

  字典的复制方法可以复制字典。

  在[16]:导入副本

  #创建字典

  在[17]: d=dict(姓名=张三,年龄=27)

  #将字典D复制到co

  在[18]中:co=d.copy()

  #检查d和co的值。

  在[19]: d

  [19]: {“姓名”:“张三”,“年龄”:27}

  在[20]: co

  [20]: { 姓名:张三,年龄:27}

  #看看D和co的记忆值,可以看出它们是不一样的。

  在[21]中:id(d)

  Out[21]: 140089352402120

  在[22]中:id(c)

  Out[22]: 140089352809416

  在[23]中:

  #然后直接为d设置新的字典内容。

  In [23]: d=dict(姓名=张三,年龄=27,儿童_年龄=[11,22])

  在[24]: d

  Out[24]: { 姓名:张三,年龄:27,儿童_年龄:[11,22]}

  在[26]: co

  [26]: { 姓名:张三,年龄:27}

  #再次将D复制到co

  在[27]: co=d.copy()

  在[28]: co

  Out[28]: { 姓名:张三,年龄:27,儿童_年龄:[11,22]}

  #将列表编号9添加到字典中的children_ages

  在[29]: d[儿童_年龄]。追加(9)

  #你可以看到co也跟着变了,说明children_ages的内存地址是一致的。

  在[30]: d

  Out[30]: { 姓名:张三,年龄:27,儿童_年龄:[11,22,9]}

  在[31]: co

  Out[31]: { 姓名:张三,年龄:27,儿童_年龄:[11,22,9]}

  在[32]中:

  In [32]: id(d[children_ages])

  Out[32]: 140089267051336

  In [33]: id(co[children_ages])

  Out[33]: 140089267051336

  在[34]中:

  4.注意轻拷贝和不可变拷贝的区别。

  对于可变类型,将进行浅层复制。Copy对于不可变类型,不会复制,只指向# copy列表可变类型。

  在[34]中:a=[11,22,33]

  在[35]中:b=copy.copy(a)

  在[36]中:id(a)

  Out[36]: 140089256561608

  在[37]中:id(b)

  Out[37]: 140089352086664

  在[38]中:a .追加(44)

  在[39]中

  Out[39]: [11,22,33,44]

  在[40]: b

  Out[40]: [11,22,33]

  在[41]中:

  #再用元祖来论证。可以看到复制的两个变量的内存地址是一致的。

  在[41]中:a=(11,22,33)

  在[42]中:b=copy.copy(a)

  [43]同上(a)

  Out[43]: 140089283270624

  在[44]中:id(b)

  Out[44]: 140089283270624

  在[45]中:

  copy.copy和copy.deepcopy的区别

  复制复制

  在[45]中:a=[11,22]

  #用元组把A括起来,那么后续的内存地址就不会改变。

  在[46]中:b=(a,)

  在[47]中

  Out[47]: ([11,22],)

  在[48]中:c=[b,]

  在[49]: c

  Out[49]: [([11,22],)]

  #用D轻拷贝C,那么C中的元组内存地址会发生变化吗?

  在[50]中:d=copy.copy(c)

  在[51]: d

  Out[51]: [([11,22],)]

  #先检查变量C和D的内存地址,发现不一样,正常。

  [52]同上(c)

  Out[52]: 140089267047816

  在[53]中:id(d)

  Out[53]: 140089352213384

  #看C和D的元组内存地址,发现是一样的,所以是原变量a的地址。

  在[57]: id(c[0])

  Out[57]: 140089352719216

  在[58]: id(d[0])

  Out[58]: 140089352719216

  #给变量A加33,那么C和D将同时增加,如下所示:

  在[54]中:a .追加(33)

  在[55]: c

  Out[55]: [([11,22,33],)]

  在[56]中:d

  Out[56]: [([11,22,33],)]

  让我们来看看完成使用可变列表的例子。

  在[60]中:a=[11,22]

  在[61]中:b=[a]

  在[62]中

  Out[62]: [[11,22]]

  在[63]中:c=[b]

  在[64]: c

  Out[64]: [[[11,22]]]

  在[65]中:d=copy.copy(c)

  在[66]中:d

  Out[66]: [[[11,22]]]

  在[67]中:id(d)

  Out[67]: 140089282147016

  在[68]中:id(c)

  Out[68]: 140089352347848

  在[69]: id(d[0])

  Out[69]: 140089356847432

  在[70]: id(c[0])

  Out[70]: 140089356847432

  在[71]: id(d[0][0])

  Out[71]: 140089282502536

  在[72]: id(c[0][0])

  Out[72]: 140089282502536

  在[73]: c

  Out[73]: [[[11,22]]]

  在[74]: d

  Out[74]: [[[11,22]]]

  在[75]中

  出[75]: [11,22]

  在[76]中:a .追加(33)

  在[77]: c

  Out[77]: [[[11,22,33]]]

  在[78]: d

  Out[78]: [[[11,22,33]]]

  在[79]中

  Out[79]: [11,22,33]

  在[80]:从上面的操作来看,只要是浅拷贝的变量,所有的内部数据都会指向同一个内存地址。

  副本.深层副本

  关注微信微信官方账号,回复【数据】,Python,PHP,JAVA,web,即可获取Python,PHP,JAVA,前端等视频数据。

  来自海洋的渔夫原创作品,

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: