关于Python中的深拷贝与浅拷贝问题探讨

【Python】关于Python中的深拷贝与浅拷贝问题探讨


Python中关于对象拷贝问题,总而言之:如果一个对象及其所包含的元素 均为不可变数据类型,那么浅拷贝(copy.copy)和深拷贝(copy.deepcopy)结果一样,都只是保持 引用指向关系。如果一个对象及其所包含的元素 只要有一个为可变数据类型那么对于浅拷贝copy.copy)还是只保持引用指向关系,但是对于深拷贝(copy.deepcopy)则会将全部拷贝一份
【注意】:切片操作(例如 list_a = list_b[ : ])和字典的 copy( )方法均属于浅拷贝操作。

下面通过以下代码逐一论证:
首先看第一种情况:

import copy

a = (1, 2)
b = [3, 4, a]
c = copy.copy(b)
d = copy.deepcopy(b)
print(id(b))  # --->14634696
print(id(c))  # --->75499600
print(id(d))  # --->14633288
print(id(b[0]) == id(c[0]))  # --->True
print(id(b[2]) == id(c[2]))  # --->True
print(id(b[0]) == id(d[0]))  # --->True
print(id(b[2]) == id(d[2]))  # --->True

a为元组(不可变数据类型),b为列表(可变数据类型),通过id()函数获取对象的存储地址后,发现对象b,c,d的存储地址均不一样,也即c和d确实被拷贝了一份。但是b,c和d中的元素地址却相同,可以证明,虽然c和d被拷贝了一份,但是他们中的元素引用于b中的元素,并没有复制。

再看第二种情况:

import copy

a1 = (1, 2)
b1 = (3, 4, a1)
c1 = copy.copy(b1)
d1 = copy.deepcopy(b1)
print(id(b1))  # --->10839168
print(id(c1))  # --->10839168
print(id(d1))  # --->10839168
print(id(b1[0]) == id(c1[0]))  # --->True
print(id(b1[2]) == id(c1[2]))  # --->True
print(id(b1[0]) == id(d1[0]))  # --->True
print(id(b1[2]) == id(d1[2]))  # --->True

a1为元组(不可变数据类型),b1为元组(不可变数据类型),通过id()函数获取对象的存储地址后,发现对象b1,c1,d1的存储地址以及他们中的元素的地址都一样,也即c1和d1对象只是保持与b1之间的引用指向关系,在内存中他们为同一个对象。

再看第三种情况:

import copy

a2 = [1, 2]
b2 = (3, 4, a2)
c2 = copy.copy(b2)
d2 = copy.deepcopy(b2)
print(id(b2))  # --->10962336
print(id(c2))  # --->10962336
print(id(d2))  # --->14284768
print(id(b2[0]) == id(c2[0]))  # --->True
print(id(b2[2]) == id(c2[2]))  # --->True
print(id(b2[0]) == id(d2[0]))  # --->True
print(id(b2[2]) == id(d2[2]))  # --->False

a2为列表(可变数据类型),b1为元组(不可变数据类型),通过id()函数获取对象的存储地址后,发现对象b2和c2的存储地址一样,但d2与b2的存储地址却不一样,同时可以看出,b2和c2中的元素存储地址也一样,b2与d2之间的元素地址不同,说明:b2和c2是同一个对象,对于b2与d2之间,首先我们可以知道d2对象被拷贝了一份,对于d2中的元素来说,其不可变的元素引用于b2,可变元素(a2)被完全复制了一份(深拷贝)。

看最后一种情况:

import copy

a3 = [1, 2]
b3 = [3, 4, a3]
c3 = copy.copy(b3)
d3 = copy.deepcopy(b3)
print(id(b3))  # --->14467656
print(id(c3))  # --->14432968
print(id(d3))  # --->14380552
print(id(b3[0]) == id(c3[0]))  # --->True
print(id(b3[2]) == id(c3[2]))  # --->True
print(id(b3[0]) == id(d3[0]))  # --->True
print(id(b3[2]) == id(d3[2]))  # --->False

a3为列表(可变数据类型),b3为列表(可变数据类型),通过id()函数获取对象的存储地址后,发现对象b3与c3、d3的存储地址均不一样,同时可以看出,b3和c3中的不可变数据类型的元素存储地址一样,但可变数据类型的元素存储地址不一样,说明:可变数据类型被完全拷贝了一份,而不可变数据类型元素只是保持引用指向关系,同理,d3也被复制了一份,但b3的不可变数据类型元素和可变数据类型元素均不同,说明d3被完全拷贝了一份(深拷贝)。

以上四种情况可以用如下图表达:
在这里插入图片描述
【注】:表格中,蓝色块代表内存地址,箭头表示引用指向关系,拿情况1来说,b、c和d三个对象分别绑定不同的内存地址,但是他们内存中的元素却引用于b对象。也即,当你用c[0]来获取c中一个元素,其实得到的是b中的第一个元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值