欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python深拷贝与浅拷贝

程序员文章站 2022-12-29 16:51:51
可变对象与不可变对象 要理解深拷贝和浅拷贝,首先要理解可变对象和不可变对象。 不可变对象:该对象所指向的内存中的值不能被改变,修改对象的值时,由于其指向的值不能被改变,因此实际上是在内存中重新开辟一个地址用来存储新的值,然后将对象指向这个新值。本质上是两个对象,赋值前后对象id发生了变化。pytho ......

可变对象与不可变对象

要理解深拷贝和浅拷贝,首先要理解可变对象和不可变对象。

不可变对象:该对象所指向的内存中的值不能被改变,修改对象的值时,由于其指向的值不能被改变,因此实际上是在内存中重新开辟一个地址用来存储新的值,然后将对象指向这个新值。本质上是两个对象,赋值前后对象id发生了变化。python中的不可变对象包括:bool、int、str、float、tuple、frozenset、none。

可变对象:该对象所指向的内存中的值可以被改变。变量(引用)的值发生改变时,实际上是其指向的值直接发生改变,没有开辟新的内存地址。python中的可变对象包括:list、dict、set。

 python中的赋值语句不会创建对象的拷贝,仅仅只是将变量名称绑定到一个对象上。对于不可变对象,这种操作不会产生差别,但是处理可变对象或可变对象的集合时,你可能希望创建这些对象的“真实拷贝”,在修改创建的拷贝时不改变原始的对象。

浅拷贝:通常指构造一个新的集合对象,然后用原始对象中的找到的子对象的引用来填充它。浅层的复制只有一层深度,复制过程中不会递归,所以不会创建子对象本身的副本。

深拷贝:深拷贝使复制过程递归,即首先构造一个新的集合对象,然后递归地用在原始对象中找到的子对象的副本来填充它。通过深拷贝复制对象,是原始对象及其所有子对象的完全独立的克隆。

赋值与引用

python的赋值语句不会复制对象,而是创建一个对象的引用(可以理解为标签)。代码示例:

python深拷贝与浅拷贝

上图示例中,创建了两个变量(实际两个变量表示的是同一个列表),但两个变量id相同,指向的是同一个内存地址。

创建浅拷贝

仍以python列表为例,通常我们会用list()函数来复制一个列表,这个复制过程,就是一个浅拷贝。代码示例:

python深拷贝与浅拷贝

可以看到,通过浅拷贝方式,确实是复制了一个列表。复制前后两个变量的id不同,两个变量指向两个不同的内存地址,且修改其中一个列表中的值,对另一个列表不会产生影响。

而之所以称这种复制方式为浅拷贝,是因为这种拷贝只对一层对象有效,当列表中有子对象时,对子对象的修改将同时影响原始对象和拷贝对象。代码示例:

python深拷贝与浅拷贝

如上图所示,修改第一层次的成员值,不会影响拷贝对象;修改子对象的成员值(第二层次),会同时影响原始对象和拷贝对象。这是因为浅拷贝没有递归复制原始对象的值,只复制了第一层,因此拷贝对象中复制了子对象的引用,并没有复制子对象的值。

创建深拷贝

python标准库中的copy模块提供了创建python对象的浅拷贝和深拷贝的接口。使用deepcopy()函数,可以创建一个对象的深拷贝。代码示例:

python深拷贝与浅拷贝

如上图所示,通过深拷贝复制的对象递归克隆了原始对象,两者是完全独立的。无论怎样修改其中一个对象,都不会对另一个对象产生影响。

总结

  • 不可变对象没有深拷贝和浅拷贝之分,可以理解为都是深拷贝
  • 创建对象的浅拷贝不会克隆子对象,不能完全对立与原始对象
  • 深拷贝会递归克隆原始对象,两者完全独立,互不影响,创建深拷贝的速度较慢