Python 学习笔记(十五):浅拷贝与深拷贝

Python 的引用计数

Python 内不可变对象的内存管理方式是引用计数,Python 不会对值相同的不可变对象申请单独的内存空间,只会记录它的引用次数,如:

import copy
a = "ironman"
b = a
c = copy.copy(a)
d = copy.deepcopy(a)

print("原字符串>>", id(a))
print("赋值操作>>", id(b))
print("浅拷贝>>", id(c))
print("深拷贝>>", id(d))
原字符串>> 140163363700784
赋值操作>> 140163363700784
浅拷贝>> 140163363700784
深拷贝>> 140163363700784

因此,Python 拷贝的主要特点都是基于可变对象的。

浅拷贝

import copy

a = ["ironman"]
b = a
c = copy.copy(a)

print("原对象>>", id(a))
print("赋值>>", id(b))
print("浅拷贝>>", id(c))
原对象>> 140378048813064
赋值>> 140261354907656
浅拷贝>> 140261354939016

赋值操作会作用于同一对象,而浅拷贝会创建一个新的对象,但对象中的元素还是会引用原来的,所以才叫 **“浅”**拷贝。

再来看下面这个例子:

import copy

a = ["ironman"]
b = a

print("修改前,a内部元素的id:", [id(i) for i in a])

c = copy.copy(a)

print("修改前,c内部元素的id:", [id(i) for i in c])

a[0] = "spiderman"

print("修改后,a内部元素的id:", [id(i) for i in a])
print("修改后,c内部元素的id:", [id(i) for i in c])

print(a)
print(c)
修改前,a内部元素的id[140209578955472]
修改前,c内部元素的id[140209578955472]
修改后,a内部元素的id[140209547805360]
修改后,c内部元素的id[140209578955472]
['spiderman']
['ironman']

浅拷贝对象中的元素不是会引用原来的吗?为什么这里 a 内元素的改变不会影响 c 内的元素?
主要是因为操作的元素是不可变对象,由于引用计数的特性,a 中被拷贝的元素被改变时不会影响 b 中已拷贝的元素,b[0] 依然指向 “ironman”。因此在操作不可变对象时,浅拷贝和深拷贝没有区别

再看另一个例子:

import copy

a = [["ironman"], "captain"]

print("修改前,a的值", a)
print("修改前,a内部元素的id:", [id(i) for i in a])

c = copy.copy(a)

print("修改前,c的值", c)
print("修改前,c内部元素的id:", [id(i) for i in c])

a[0][0] = "spiderman"
a[1] = "thanos"

print("修改后,a的值", a)
print("修改后,a内部元素的id:", [id(i) for i in a])
print("修改后,c的值", c)
print("修改后,c内部元素的id:", [id(i) for i in c])
修改前,a的值 [['ironman'], 'captain']
修改前,a内部元素的id[139705101206792, 139705132356472]
修改前,c的值 [['ironman'], 'captain']
修改前,c内部元素的id[139705101206792, 139705132356472]
修改后,a的值 [['spiderman'], 'thanos']
修改后,a内部元素的id[139705101206792, 139705131903160]
修改后,c的值 [['spiderman'], 'captain']
修改后,c内部元素的id[139705101206792, 139705132356472]

浅拷贝会使用原始元素的引用(即内存地址),所以在操作被拷贝对象内部的可变元素时,其结果会影响到拷贝对象。

深拷贝

深拷贝遇到可变对象,又会进行一层对象创建,当你操作被拷贝对象内部的可变对象时,不会影响拷贝对象的值

import copy

a = [["ironman"], "captain"]

print("修改前,a的值", a)
print("修改前,a内部元素的id:", [id(i) for i in a])

c = copy.deepcopy(a)

print("修改前,c的值", c)
print("修改前,c内部元素的id:", [id(i) for i in c])
a[0][0] = "spiderman"
a[1] = "thanos"

print("修改后,a的值", a)
print("修改后,a内部元素的id:", [id(i) for i in a])
print("修改后,c的值", c)
print("修改后,c内部元素的id:", [id(i) for i in c])
修改前,a的值 [['ironman'], 'captain']
修改前,a内部元素的id[139755102070024, 139755133219704]
修改前,c的值 [['ironman'], 'captain']
修改前,c内部元素的id[139755102069768, 139755133219704]
修改后,a的值 [['spiderman'], 'thanos']
修改后,a内部元素的id[139755102070024, 139755132766392]
修改后,c的值 [['ironman'], 'captain']
修改后,c内部元素的id[139755102069768, 139755133219704]

总结

  • 由于 python内部引用计数的特性,对于不可变对象,浅拷贝和深拷贝的作用是一致的,就相当于复制了一份副本,原对象内部的不可变对象的改变,不会影响到复制对象。

  • 浅拷贝,其实是拷贝了原始元素的引用(即内存地址),所以当拷贝可变对象时,原对象内可变对象的对应元素的改变,会影响到复制对象的对应元素。

  • 深拷贝在遇到可变对象时,又在内部新建了一个副本,不管原对象内部元素如何变化都不会影响拷贝副本的可变对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值