序列之深拷贝-浅拷贝

在上周的Python科学计算课上,老师讲到了Python序列的浅拷贝以及深拷贝方面的知识,个人觉得说得比较言简意赅了,对于我这个刚入Python的新手来说,也基本可以避免今后变量的赋值使用错乱的问题。

这里我们简单的将Python中的标准数据类型分为两类:

  • 不可变数据类型:int、float、string、boolean
  • 可变(组合)数据类型:列表(list)、字典(dict)、集合(set)

先举几个例子:

a = 1 # a为上述定义的不可变数据类型
b = a
print('b={}'.format(b)) # b = 1
--------
b = 2
print('a = {},b = {}'.format(a,b)) # a = 1,b = 2

========

c = [1,2,3] # b为上述定义的组合数据类型 
d = c
print('c = {},d = {}'.format(c,d)) # c = [1, 2, 3],d = [1, 2, 3]
d.append(4) 
print('c = {},d = {}'.format(c,d)) # c = [1, 2, 3, 4],d = [1, 2, 3, 4]

从上述的例子当中看出,在不可变数据类型中,所定义的变量的值在后来改变(这里是b),并不会引起原来赋给它值的那个量的改变(这里是a);而在组合数据类型中就发生了改变,我们只是将d的值进行了改变,并没有直接改变c的值,最后c的值却也发生了变化。

这里,基本数据变量的赋值其实就是深拷贝;组合数据类型的赋值就是起了一个别名。

这里先做出组合数据类型中赋值、浅拷贝、深拷贝三种的区别:

  • 直接赋值:其实就是对象的引用(即给对象起一个别名)。

  • 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。

  • 深拷贝(deepcopy):copy模块的deepcopy方法,完全拷贝了父对象及其子对象。

    关于内部子对象的概念,下方会再解释。

接下来我们再看一组图(上课ppt图片):

赋值引用

这里的a = {1:[1,2,3]}字典类型。b = a : 赋值引用,a 和 b 都指向同一个对象。可以看出,a,b此刻都指向同一个对象,所以改变b的内容,就是在改变a,b同时所指向的对象的内容,可以理解成b就是a的一个别名。

浅拷贝

这里 a = {1:[1,2,3]} , b = a.copy(),这里就是一种浅拷贝的方式。可以看出a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。所以在这里L,M就是对象当中的一个子对象([1,2,3])便是这里的子对象。

举个上述的例子:

import copy
a = {1:[1,2,3],'北京':'天安门'}
b = copy.copy(a) # b = {1:[1,2,3],'北京':'天安门'}
b[1].append(4) 
b['上海'] = '东方明珠'
b['北京'] = '鸟巢'
print('输出:a = {},b = {}'.format(a,b))

-----
输出:a = {1: [1, 2, 3, 4], '北京': '天安门'},b = {1: [1, 2, 3, 4], '北京': '鸟巢', '上海': '东方明珠'}

b = copy.copy(a) 使得b为单独一个对象,但是它和a的子对象指向统一对象。这里的子对象就是[1,2,3](列表子对象)。故当改变b中1键对中的值[1,2,3]时,a也会改变(统一子对象)。但向b中添加值时,便不会对a造成影响,因为这是b自身的对象所拥有的值(和a没有关系)。

那么如何拷贝一个a,但对这个拷贝的对象任意操作时,不会对a产生任何的影响呢?答:采用深拷贝。

如图:

深拷贝

从图中可以清楚的看出:深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。

import copy
a = [1, 2, 3, 4, ['a', 'b']]    #原始对象  
b = a                           #赋值,传对象的引用
c = copy.copy(a)                #对象拷贝,浅拷贝
d = copy.deepcopy(a)            #对象拷贝,深拷贝
a.append(5)                     #修改对象a
a[4].append('c')                #修改对象a中的['a', 'b']数组对象

print( 'a = ', a )
print( 'b = ', b )
print( 'c = ', c )
print( 'd = ', d )

--------
a =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b =  [1, 2, 3, 4, ['a', 'b', 'c'], 5] # 给a起了一个别名b,本质相同,故b和a的变化相同
c =  [1, 2, 3, 4, ['a', 'b', 'c']]    # c中子对象发生了变化 -->浅拷贝
d =  [1, 2, 3, 4, ['a', 'b']]         # a的改变和d无关 -->深拷贝

总结

对于组合数据类型:

  • 直接赋值:其实就是对象的引用(别名)

  • 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象

  • 深拷贝(deepcopy):copy模块的deepcopy方法,完全拷贝了父对象及其子对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值