浅谈python的深拷贝和浅拷贝

本文深入探讨了Python中列表拷贝的三种方式:别名、浅拷贝和深拷贝,解析了每种方式下列表元素的内存地址变化,以及如何在不影响原列表的情况下进行修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

	考虑一个场景:在该场景中,我们有各种列表的颜色,每个颜色代表假定颜色类的一个
实例。我们让标识符a表示现有的颜色列表。在这个应用中,我们希望创建一个名为b的新列
表,复制一份b列表。达到修改、删除、添加b中的颜色而不影响到a列表。
1、第一种情况:(创建别名)

假设a = [“red”,“blue”,“green”],如果执行命令b = a,这样仅仅是创建了这个列表的一个别名,a和b是指向同一个列表对象,它们的内存地址是一样的。

a = ["red","blue","green"]
b = a
print(id(a),id(b))#2253502304840 2253502304840

a[0] = "yellow"
print(a,b)
#['yellow', 'blue', 'green'] ['yellow', 'blue', 'green']

因为是a和b代表的是同一个列表对象,那么修改a其实就是在修改b.

2、第二种情况:(浅拷贝)

我们用构造函数创建一个新的列表实例:b = list(a),这种方式就被称为浅拷贝。

我们写一个代码来分析一下:

a = ["red","blue","green"]
b = list(a)

print(id(a),id(b))#2161162736200 2161193156104
print(id(a[0]),id(b[0]))#2161163276144 2161163276144
a[0] = "yellow"
print(a,b)#['yellow', 'blue', 'green'] ['red', 'blue', 'green']
print(id(a[0]),id(b[0]))#2161193327984 2161163276144

我们通过代码打印的结果来分析一下:

  • a、b的内存地址是不一样的,这个因为a和b是不同的对象,a和b自然就是占用不同的内存空间的。
  • 但是我们发现a、b的第一个元素的内存地址为什么是一样的呢?其实这个主要是python的list采用的是引用数组,这里虽然a和b是两个截然不同的对象,但是它们其中的元素却是相同的元素,只是在a和b中是两个指向同一元素地址空间的别名。
  • 相信有的同学在第二条可能会有点迷惑,既然说a和b里的元素其实是指向的同一个元素,那么为什么在修改之后,打印出来的却是两个不同的元素呢?以x = 2为例,y = x,假设x = x+1,那么x=3,y=2,这里不也是吗,x和y指向同一个元素2,但是修改了x之后,y的值却是不会变化的,因为这里的元素是不可变对象,x = x+1之后,x已经不是原来的那个x了。看下面的不可变对象a[0]。
import copy
a = [[1,2,3],"red","blue","green"]

# b = copy.deepcopy(a)
b = list(a)
print(id(a),id(b))
print(id(a[0]),id(b[0]))
a[0].append(4)
print(a,b)#[[1, 2, 3, 4], 'red', 'blue', 'green'] [[1, 2, 3, 4], 'red', 'blue', 'green']
print(id(a[0]),id(b[0]))#2226783836168 2226783836168
  • 因为a[0]是一个列表,是不可变对象,可以对a[0]进行修改,我们看到之后的内存地址也不会发生变化。

注:所以浅拷贝只拷贝一层的说法也是由此而来。

3、第三种情况:(深拷贝)

直接看代码:

import copy
a = [[1,2,3],"red","blue","green"]

b = copy.deepcopy(a)
# b = list(a)
print(id(a),id(b))
print(id(a[0]),id(b[0]))
a[0].append(4)
print(a,b)#[[1, 2, 3, 4], 'red', 'blue', 'green'] [[1, 2, 3], 'red', 'blue', 'green']
print(id(a[0]),id(b[0]))#2453682903112 2453682902920
  • 从上面的代码就可以看出,这里a和b的元素就不存在别名的关系了,它们是实实在在的两个对象,对一个操作并不会对另一个产生影响。

注:善于尝试的同学可能会发现,上面深拷贝的这个代码print(id(a[1]),id(b[1]))的内存地址是一样的,这里主要是数据池对字符串造成的影响,有兴趣的可以自己去了解一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值