首页 » 智能 » 一文理解Python深拷贝与浅拷贝问题_对象_赋值

一文理解Python深拷贝与浅拷贝问题_对象_赋值

乖囧猫 2024-12-04 17:42:47 0

扫一扫用手机浏览

文章目录 [+]

Python工具

在Python中,对工具有一种很普通的说法,万物皆工具。
说的便是布局的任何数据类型都是一个工具,无论是数字,字符串,还是函数,乃至是模块,Python都对当做工具处理。

一文理解Python深拷贝与浅拷贝问题_对象_赋值 智能

所有Python工具都拥有三个属性:身份、类型、值。

看一个大略的例子:

In [1]: name = \"大众laowang\"大众 # name工具In [2]: id(name) # id:身份的唯一标识Out[2]: 1698668550104In [3]: type(name) # type:工具的类型,决定了该工具可以保存什么类型的值Out[3]: strIn [4]: name # 工具的值,表示的数据Out[4]: 'laowang'

可变与不可变工具

在Python中,按更新工具的办法,可以将工具分为2大类:可变工具与不可变工具。

可变工具: 列表、字典、凑集所谓可变是指可变工具的值可变,身份是不变的。
不可变工具:数字、字符串、元组不可变工具便是工具的身份和值都不可变。
新创建的工具被关联到原来的变量名,旧工具被丢弃,垃圾回收器会在适当的机遇回收这些工具。

In [7]: var1 = \"大众python\"大众In [8]: id(var1)Out[8]: 1700782038408#由于var1是不可变的,重新创建了java工具,随之id改变,旧工具python会在某个时候被回收In [9]: var1 = \"大众java\"大众In [10]: id(var1) Out[10]: 1700767578296

引用

在 Python 程序中,每个工具都会在内存中申请开辟一块空间来保存该工具,该工具在内存中所在位置的地址被称为引用。
在开拓程序时,所定义的变量名实际就工具的地址引用。

引用实际便是内存中的一个数字地址编号,在利用工具时,只要知道这个工具的地址,就可以操作这个工具,但是由于这个数字地址未便利在开拓时利用和影象,以是利用变量名的形式来代替工具的数字地址。
在 Python 中,变量便是地址的一种表示形式,并不开辟开辟存储空间。

就像 IP 地址,在访问网站时,实际都是通过 IP 地址来确定主机,而 IP 地址未便利影象,以是利用域名来代替 IP 地址,在利用域名访问网站时,域名被解析成 IP 地址来利用。

通过一个例子来解释变量和变量指向的引用便是一个东西

In [11]: age = 18In [12]: id(age)Out[12]: 1730306752In [13]: id(18)Out[13]: 1730306752逐步深入:引用赋值

上边已经明白,引用便是工具在内存中的数字地址编号,变量便是方便对引用的表示而涌现的,变量指向的便是此引用。
赋值的实质便是让多个变量同时引用同一个工具的地址。
那么在对数据修正时会发生什么问题呢?

不可变工具的引用赋值对不可变工具赋值,实际便是在内存中开辟一片空间指向新的工具,原不可变工具不会被修正。
事理图如下:

下面通过案例来理解一下:

a与b在内存中都是指向1的引用,以是a、b的引用是相同的

In [1]: a = 1In [2]: b = aIn [3]: id(a)Out[3]: 1730306496In [4]: id(b)Out[4]: 1730306496

现在再给a重新赋值,看看会发生什么变革?

从下面不丢脸出:当给a 赋新的工具时,将指向现在的引用,不在指向旧的工具引用。

In [1]: a = 1In [2]: b = aIn [5]: a = 2In [6]: id(a)Out[6]: 1730306816In [7]: id(b)Out[7]: 1730306496可变工具的引用赋值可变工具保存的并不是真正的工具数据,而是工具的引用。
当对可变工具进行赋值时,只是将可变工具中保存的引用指向了新的工具。

事理图如下:

仍旧通过一个实例来体会一下,可变工具引用赋值的过程。

当改变l1时,全体列表的引用会指新的工具,但是l1与l2都是指向保存的同一个列表的引用,以是引用地址不会变。

In [3]: l1 = [1, 2, 3]In [4]: l2 = l1In [5]: id(l1)Out[5]: 1916633584008In [6]: id(l2)Out[6]: 1916633584008In [7]: l1[0] = 11In [8]: id(l1)Out[8]: 1916633584008In [9]: id(l2)Out[9]: 1916633584008主旨详解:浅拷贝、深拷贝

经由前2部分的解读,大家对工具的引用赋值该当有了一个清晰的认识了。

下面大家思考一个这样的问题:Python中如何办理原始数据在函数通报之后不受影响了?

这个问题Python已经帮我们办理了,利用工具的拷贝或者深拷贝就可以愉快的办理了。

下面详细来看看Python中的浅拷贝与深拷贝是如何实现的。

浅拷贝:

为理解决函数通报后被修正的问题,就须要拷贝一份副本,将副本通报给函数利用,就算是副本被修正,也不会影响原始数据 。

不可变工具的拷贝

不可变工具只在修正的时候才会在内存中开辟新的空间, 而拷贝实际上是让多个工具同时指向一个引用,和工具的赋值没差异。

同样的,通过一个实例来感想熏染一下:不丢脸出,a与b指向相同的引用,不可变工具的拷贝便是工具赋值。

In [11]: import copyIn [12]: a = 10In [13]: b = copy.copy(a)In [14]: id(a)Out[14]: 1730306496In [15]: id(b)Out[15]: 1730306496

可变工具的拷贝

对付不可变工具的拷贝,工具的引用并没有发生变革,那么可变工具的拷贝会不会和不可变工具一样了?我们接着往下看。

通过下面这个实例可以看出:可变工具的拷贝,会在内存中开辟一个新的空间来保存拷贝的数据。
当再改变之前的工具时,对拷贝之后的工具没有任何影响。

In [24]: import copyIn [25]: l1 = [1, 2, 3]In [26]: l2 = copy.copy(l1)In [27]: id(l1)Out[27]: 1916631742088In [28]: id(l2)Out[28]: 1916636282952In [29]: l1[0] = 11In [30]: id(l1)Out[30]: 1916631742088In [31]: id(l2)Out[31]: 1916636282952

事理图如下:

现在再回到刚才那个问题,是不是浅拷贝就可以办理原始数据在函数通报之后不变的问题了?下面看一个轻微繁芜一点的数据构造。

通过下面这个实例可以创造:繁芜工具在拷贝时,并没有办理数据在通报之后,数据改变的问题。
涌现这种缘故原由,是copy() 函数在拷贝工具时,只是将指定工具中的所有引用拷贝了一份,如果这些引用当中包含了一个可变工具的话,那么数据还是会被改变。
这种拷贝办法,称为浅拷贝。

In [35]: a = [1, 2]In [36]: l1 = [3, 4, a]In [37]: l2 = copy.copy(l1)In [38]: id(l1)Out[38]: 1916631704520In [39]: id(l2)Out[39]: 1916631713736In [40]: a[0] = 11In [41]: id(l1)Out[41]: 1916631704520In [42]: id(l2)Out[42]: 1916631713736In [43]: l1Out[43]: [3, 4, [11, 2]]In [44]: l2Out[44]: [3, 4, [11, 2]]

事理图如下:

对付上边这种状况,Python还供应了另一种拷贝办法(深拷贝)来办理。

深拷贝

差异于浅拷贝只拷贝顶层引用,深拷贝会逐层进行拷贝,直到拷贝的所有引用都是不可变引用为止。

接下来我们看看,假如将上边的拷贝实例用利用深拷贝的话,原始数据改变的问题还会不会存在了?

下面的实例清楚的见告我们:之前的问题就可以完美办理了。

import copyl1 = [3, 4, a]In [47]: l2 = copy.deepcopy(li)In [48]: id(l1)Out[48]: 1916632194312In [49]: id(l2)Out[49]: 1916634281416In [50]: a[0] = 11In [51]: id(l1)Out[51]: 1916632194312In [52]: id(l2)Out[52]: 1916634281416In [54]: l1Out[54]: [3, 4, [11, 2]]In [55]: l2Out[55]: [1, 2, 3]

事理图如下:

查漏补缺

为什么Python默认的拷贝办法是浅拷贝?

韶光角度:浅拷贝花费韶光更少空间角度:浅拷贝花费内存更少效率角度:浅拷贝只拷贝顶层数据,一样平常情形下比深拷贝效率高。

本文知识点总结:

不可变工具在赋值时会开辟新空间可变工具在赋值时,修正一个的值,另一个也会发生改变深、浅拷贝对不可变工具拷贝时,不开辟新空间,相称于赋值操作浅拷贝在拷贝时,只拷贝第一层中的引用,如果元素是可变工具,并且被修正,那么拷贝的工具也会发生变革深拷贝在拷贝时,会逐层进行拷贝,直到所有的引用都是不可变工具为止。
Python 中有多种办法实现浅拷贝,copy模块的copy 函数 ,工具的 copy 函数 ,工厂方法,切片等。
大多数情形下,编写程序时,都是利用浅拷贝,除非有特定的需求浅拷贝的优点:拷贝速率快,占用空间少,拷贝效率高
标签:

相关文章