python篇 深拷贝与浅拷贝

本文详细介绍了Python中的拷贝概念,包括浅拷贝和深拷贝的区别。浅拷贝仅拷贝对象的第一层,子对象会被直接引用,而深拷贝则通过递归实现对对象及其所有子对象的完整拷贝。通过实例演示,展示了如何使用列表的copy方法和copy模块的深浅拷贝功能,以及它们在面对复杂对象时的行为。建议在需要完全分离对象时使用深拷贝,以避免修改一个对象会影响到另一个。
摘要由CSDN通过智能技术生成

1.拷贝概念

如果各位捧场的读者老爷对python中‘’is‘’和‘’==‘’运算符的概念如我一样有些许了解的话,那应该知道当我们在将一个变量赋予另一个变量如“a = b ”时,如果b的值在小整型缓存区(-5~256)内,那么所谓的将b值赋值给a就只是引用同一个内存数据罢了。深拷贝浅拷贝有点类似于这个,“浅”字在这里的意思就是浅浅一层,仅能能拷贝对象的表层,而其子对象,就是直接拿来引用了,所谓深拷贝就是用递归的原理把其子对象也依次拷贝下来,这就是两者的区别。

百般口舌不如一证,下面举些小例子用以说明,如果基础较差的读者可以按情况点击下面链接查看笔记。

1.2 相关知识点

python篇 “is"和”=="
python篇 变量应用
python篇 面向对象

2.浅拷贝概念

由上述定义可知,所谓浅拷贝即是只拷贝对象第一层而不拷贝其子对象。

3.浅拷贝演示

对于列表的拷贝我们可以使用列表内置的copy方法,当然也可以使用copy模块的copy方法,都会讲到。废话不说了,开搞。

>>> ls1 = [1,2,3,4,5]
>>> ls2 = ls.copy()
>>> ls1
[1, 2, 3, 4, 5]
>>> ls2
[1, 2, 3, 4, 5]

列表中的copy方法是浅拷贝,我们定义了ls1变量并赋值了一个列表对象,接着又把对象拷贝给了ls2,可以用内置方法id()查看拷贝后类ls1、ls2的内存地址,当然结果大家也应该知道浅拷贝是能拷贝对象第一层的,而非只是引用,所以内存地址必然不同。

>>> id(ls1)
744702724096
>>> id(ls2)
744702724160

故而在改变其中一个的值时另一个的值也不会改变

>>> ls1.append(6)
>>> ls1
[1, 2, 3, 4, 5, 6]
>>> ls2
[1, 2, 3, 4, 5]

但若是为需要拷贝的内容加上子对象呢?已经讲过子对象无法被浅拷贝所拷贝,这里我们就为ls1重新赋值加上一个列表子对象,再将其拷贝。

>>> ls1 = [1,2,3,[4,5,6]]
>>> ls2 = ls1.copy()
>>>> ls1
[1, 2, 3, [4, 5, 6]]
>>> ls2
[1, 2, 3, [4, 5, 6]]
>>> id(ls1)
744702725824
>>> id(ls2)
744702726080

如上面代码所示,第一层对象的拷贝是成功了的,但子对象…

>>> id(ls1[3])
744702460544
>>> id(ls2[3])
744702460544
>>>

就只是简单引用了,既然是引用的是同一个内存数据,那么我改变其中一个,另一个自然也要改变。

>>> ls1
[1, 2, 3, [4, 5, 6]]
>>> ls2
[1, 2, 3, [4, 5, 6]]
>>> ls1[3].append(9)
>>> ls1
[1, 2, 3, [4, 5, 6, 9]]
>>> ls2
[1, 2, 3, [4, 5, 6, 9]]
>>>

为了方便拷贝,python中提供了对象拷贝模块,copy模块
用import copy命令引入该模块

import copy

在copy模块下亦有一个copy方法(copy.copy)与列表自带的copy方法功能相同,也是浅拷贝,就不多加赘述了,只是提一下,因为深拷贝要用到

>>> ls = [1,2,3,[1,2,3],4]
>>> ls2 = ls.copy()
>>> id(ls2[3]) //第二层
375434153856
>>> id(ls[3])  //第二层
375434153856
>>> ls[3][2]=22222   //操作子对象
>>> ls
[1, 2, 3, [1, 2, 22222], 4]
>>> ls2
[1, 2, 3, [1, 2, 22222], 4]
>>> ls1 = copy.copy(ls)
>>> ls1
[1, 2, 3, [1, 2, 22222], 4]
>>> ls
[1, 2, 3, [1, 2, 22222], 4]
>>> id(ls)
375433973184
>>> id(ls[3])
375434153856
>>> id(ls1[3])
375434153856

4.深拷贝概念

由上述定义可知,所谓深拷贝即是拷贝对象并拷贝对象下的子对象。

5.深拷贝演示

我们已经了解了深拷贝的概念,现在具体使用,为了方便使用,我们这里也使用copy模块进行拷贝,而深拷贝的底层逻辑,是使用的递归原理完成拷贝,如果对递归概念不太了解可以点击下面的链接。
python篇 递归使用

下面介绍copy模块中另一个“copy”方法,也就是深拷贝方法:
copy.deepcopy,下面我们定义一个含有子对象的ls变量,并用深拷贝给ls1变量

>>> ls
[1, 2, 3, [1, 2, 22222], 4]
>>> ls1 = copy.deepcopy(ls)
>>> ls1
[1, 2, 3, [1, 2, 22222], 4]

同样用全局函数id查看其子对象内存地址,可知其子对象内存地址值不同,已完成拷贝,而非简单引用。

>>> id(ls[3])
744702914816
>>> id(ls1[3])
744702725824

理所应该的改变其中一个的子对象,另一个不会发生改变。


>>> ls
[1, 2, 3, [1, 2, 22222], 4]
>>> ls[3].append("哈哈哈")
>>> ls
[1, 2, 3, [1, 2, 22222, '哈哈哈'], 4]
>>> ls1
[1, 2, 3, [1, 2, 22222], 4]

下面做个小总:

一般需要拷贝对象的时候,一般建议大家使用拷贝为浅拷贝,只拷贝一层,效率会高一点,占用内存会少一点,如果需要完全分离就使用深拷贝;
特殊情况:不可变类型(元组,字符串),无论浅拷贝还是深拷贝都永远只有一份(引用)

出道题感兴趣的可以下去尝试:

元组中的元素是可变的,浅拷贝和深拷贝会发生啥?

>>> t = (1,2,[3,4,5])
>>> tt = copy.copy(t)
>>> ttt = copy.deepcopy(t)
>>> ttt = copy.deepcopy(t)
>>> t is tt
True
>>> t is ttt
False
>>>

答曰:会全数复制一份其不可变对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值