python中的深浅拷贝

1 可变和不可变的数据类型

在Python3中,有6个标准的数据类型,分为可以变和不可变。
不可变:Number(数字)、String(字符串)、Tuple(元组)。
可以变:List(列表)、Dictionary(字典)、Set(集合)。

2 浅拷贝

2.1 浅拷贝的实现

  1. li.copy()
  2. li[:]
  3. copy.copy()

2.2 浅拷贝的总结

1、对于不可变类型 Number ,String ,Tuple,浅拷贝仅仅是地址指向,不会开辟新空间。
2、对于可变类型 List,Dictionary,Set,浅拷贝会开辟新的空间地址(仅仅是最外层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝。
3、浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。(操作拷贝对象对原始对象的也是同理)

2.3 可变类型和不可变类型在浅拷贝中的举例

对于不可变类型Number ,String ,Tuple,浅拷贝仅仅是地址指向,不会开辟新空间。

import copy
num1 = 1
num2 =copy.copy(num1)
print(id(num1),id(num2))
#字符串
num1 = 'asd'
num2 =copy.copy(num1)
print(id(num1),id(num2))
#tuple
num1 = (12,'dd')
num2 =copy.copy(num1)
print(id(num1),id(num2))

结果是:

1493297072 1493297072
5755904 5755904
2732712 2732712

```python
import copy
#数值
num1 = 1
num2 =copy.deepcopy(num1)
print(id(num1),id(num2))
#字符串
num1 = 'asd'
num2 =copy.deepcopy(num1)
print(id(num1),id(num2))
#tuple
num1 = (12,'dd')
num2 =copy.deepcopy(num1)
print(id(num1),id(num2))

结果是:

1490610096 1490610096
31511552 31511552
2863784 2863784

对于可变类型List,Dictionary,Set,浅拷贝会开辟新的空间地址(仅仅是最外层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝。

import copy
#set
num1 = {'asd','d'}
num2 =copy.copy(num1)
print(id(num1),id(num2))
#tuple
num1 = [12,'dd']
num2 =copy.copy(num1)
print(id(num1),id(num2))
#dict
num1 = {12:'dd',13:'d'}
num2 =copy.copy(num1)
print(id(num1),id(num2))

结果是;

4922584 4922472
5406216 5406088
2312304 2312384
import copy
#set
num1 = {'asd','d'}
num2 =copy.deepcopy(num1)
print(id(num1),id(num2))
#tuple
num1 = [12,'dd']
num2 =copy.deepcopy(num1)
print(id(num1),id(num2))
#dict
num1 = {12:'dd',13:'d'}
num2 =copy.deepcopy(num1)
print(id(num1),id(num2))

结果是:

3022040 3021928
10976776 10976648
2771056 3029224

从上面两个深拷贝的例子来看,我们对3种可变类型3种不可变类型进行深拷贝。结果发现,和浅拷贝几乎一致。
其实这也好理解,因为的深拷贝对比浅拷贝,强调的是递归,强调的是资源素。
对于外层的操作,深浅拷贝无异。
对于不可变数据类型,深拷贝依然是地址指向,不会开辟新空间拷贝值。对于可变类型,深拷贝会开辟新的空间地址,进行拷贝。

2.4 浅拷贝后对可变和不可变修改后的影响

import copy

l1 = [11, 12]
l2 = [21, 22]
num = 555

allOne = [l1, l2,num]

# 浅拷贝,创建出一个对象,并把旧对象元素的 引用地址 拷贝到新对象当中。
# 也就是说,两个对象里面的元素通过浅拷贝指向的还是同一个地址
qiankaobei = copy.copy(allOne)

l1[0] = 16 # 此处修改,会使得 allOne 和 qiaokaobei的第0个元素的值都发生改变,因为l1是List,是可变对象
allOne[2] = 666 # 此处修改,只会allOne的num的值,因为不可变对象一旦重新复制,地址就会发生改变。

num = 777 # 此处不会改变 allOne 和 qiankaobei的值,因为相当于 777 复制给一个全新的地址,这个num跟其他num已经没关系了

print(allOne)
print(qiankaobei)

print("id allOne:"+str(id(allOne)))
print("id allOne[0]:"+str(id(allOne[0])))
print("id allOne[1]:"+str(id(allOne[1])))
print("id allOne[2]:"+str(id(allOne[2])))
print("id qiankaobei:"+str(id(qiankaobei)))
print("id qiankaobei:"+str(id(qiankaobei[0])))
print("id qiankaobei:"+str(id(qiankaobei[1])))
print("id qiankaobei:"+str(id(qiankaobei[2])))

l1 = [11, 12]
l2 = [21, 22]
haha = 555

allOne = [l1, l2,haha]
shenkaobei = copy.deepcopy(allOne)

l1[0] = 16
allOne[2] = 666

haha = 777

print(allOne)
print(shenkaobei)

print("id allOne:"+str(id(allOne)))
print("id allOne[0]:"+str(id(allOne[0])))
print("id allOne[1]:"+str(id(allOne[1])))
print("id allOne[2]:"+str(id(allOne[2])))
print("id shenkaobei:"+str(id(shenkaobei)))
print("id shenkaobei:"+str(id(shenkaobei[0])))
print("id shenkaobei:"+str(id(shenkaobei[1])))
print("id shenkaobei:"+str(id(shenkaobei[2])))

结果是:

[[16, 12], [21, 22], 666]
[[16, 12], [21, 22], 555]
id allOne:4341288
id allOne[0]:4341160
id allOne[1]:4210888
id allOne[2]:4292816
id qiankaobei:4341032
id qiankaobei:4341160
id qiankaobei:4210888
id qiankaobei:4292800
[[16, 12], [21, 22], 666]
[[11, 12], [21, 22], 555]
id allOne:4341224
id allOne[0]:4341192
id allOne[1]:4341256
id allOne[2]:4292816
id shenkaobei:4341288
id shenkaobei:4341352
id shenkaobei:4341384
id shenkaobei:4292800

3 简述深浅拷贝和赋值三者区别。

直接赋值(li1 = li): 只传递对象的引用, li1指向对象li的内存地址空间,因此,原有列表li改变, 被赋值的li1也会做相应的改变.
浅拷贝:li和li2的内存地址不同,但是子对象的内存地址相同, 因此,原始数据改变 ,子对象也改变。
深拷贝(import copy, eg: li3=copy.deepcopy(li)), li和li3的内存地址不同,包含子对象的拷贝, 所以原始对象改变并不会造成深拷贝里面任何子项的改变。
当深拷贝和浅拷贝, 针对的对象全部是不可变数据类型时, 两者效果相同;
当深拷贝和浅拷贝, 针对的对象包含是可变数据类型时, 两者才有上述区别。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值