一节课让你彻底搞懂Python高频面试题:赋值&深浅复制

本文深入浅出地介绍了Python中的深浅复制概念,通过实例解析了两者的区别。在单层列表中,深浅复制并无明显差异,但在嵌套列表中,浅复制仅拷贝外层,而深复制则创建全新内存空间。通过代码演示,帮助读者掌握深浅复制在处理列表变化时的不同行为。

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

每篇前言:


👇
☝️

首先,我们得了解的是深浅复制究竟是个什么玩意&这玩意到底是干啥的!

打个比方:有糖纸和糖,深复制就相当于糖纸和糖都有,而浅复制就只有糖纸。(这句话牢记于心,在你看完本文后再来反复揣摩本句,如果有很深的心得体会——那么恭喜你:你已经牢牢掌握了python里的深浅复制!)


而我们怎么判断复制前后的对象究竟是不是同一个呢  ?                            
这就需要用到id(object),它返回的是对象的“身份证号”(在c++中代表在内存中的地址),唯一且不变。

令外,用is判断两个对象是否相等时,依据就是这个id值。
id查看的地址一样,可以说明它们指向的是同一片空间

1. 什么是深浅复制?

在 Python 中,赋值、浅复制(shallow copy)和深复制(deep copy)是三种不同的对象复制方式。

  • 赋值(=): 只是创建了新的变量名,并没有创建新的对象,所有变量都指向同一块内存。
  • 浅复制(shallow copy): 仅复制对象的第一层,但内层的嵌套对象仍然是共享的。
  • 深复制(deep copy): 递归地复制整个对象,包括所有嵌套对象,完全独立于原对象。

举个形象的比喻

假设我们有一个装糖果的糖纸包裹物:

  • 赋值(=):只是给糖果包裹物换个名字,并没有真正复制糖果。
  • 浅复制:创建了一个新的糖果包裹物,但里面的糖果还是原来的。
  • 深复制:既复制了糖果包裹物,也复制了里面的所有糖果,形成一个完全独立的新包装。

2. Python 赋值(=)

在 Python 中,直接使用 = 进行变量赋值时,新变量只是原对象的一个引用,两者共享同一个内存地址。

# 直接赋值
>>> a = [1, 2, 3, 4]
>>> b = a
>>> id(a), id(b)  # ID 相同
(1402582080, 1402582080)

修改 ab,都会影响到对方:

>>> a.append(5)
>>> print(b)  # b 也发生了变化
[1, 2, 3, 4, 5]

结论:赋值不会创建新的对象,仅仅是增加一个变量名指向同一块内存。

3. 浅复制(shallow copy)

浅复制创建了一个新的对象,但仅复制第一层,对于嵌套对象,仍然指向原来的内存地址。

>>> import copy
>>> li = [[1, 2], [3, 4]]
>>> li2 = copy.copy(li)

观察 lili2 的 ID:

>>> id(li), id(li2)  # li 和 li2 是两个不同的对象
(2011597308424, 2011597308360)

但它们的内层列表仍然是共享的:

>>> id(li[0]), id(li2[0])  # 第一层复制了,内层仍然指向原来的对象
(2011597305032, 2011597305032)

修改第一层不会影响 li2

>>> li.append([5, 6])
>>> print(li)  # 影响 li
[[1, 2], [3, 4], [5, 6]]
>>> print(li2)  # li2 不受影响
[[1, 2], [3, 4]]

但修改内层对象会影响 li2

>>> li[0].append(99)
>>> print(li2)  # li2[0] 也变了
[[1, 2, 99], [3, 4]]

结论:浅复制只是复制了外层对象,内层对象仍然共享。

4. 深复制(deep copy)

深复制会递归地复制整个对象,保证新对象和原对象完全独立。

>>> li3 = copy.deepcopy(li)

验证 li3li 是完全独立的:

>>> id(li), id(li3)  # 两个对象不同
(2011597308424, 2011598772872)
>>> id(li[0]), id(li3[0])  # 内层对象的 ID 也不同
(2011597305032, 2011598772936)

修改 li 任何部分,都不会影响 li3

>>> li[0].append(999)
>>> print(li)  # li 发生变化
[[1, 2, 99, 999], [3, 4]]
>>> print(li3)  # li3 没有变化
[[1, 2, 99], [3, 4]]

结论:深复制会完全独立地复制整个对象及其所有嵌套对象。

5. 深浅复制对比总结

类型是否创建新对象是否独立复制嵌套对象修改原对象是否影响副本
赋值(=)
浅复制是(嵌套对象)
深复制

(1)什么时候使用浅复制?

  • 当对象本身是简单的一维列表或字典时,可以使用 copy.copy()
  • 当你只需要复制最外层,而嵌套对象仍然可以共享时。

(2)什么时候使用深复制?

  • 当对象有多层嵌套,并且你希望完全独立时,使用 copy.deepcopy()
  • 当你要避免修改副本时影响原对象。

拓展:Python 内存池机制(小整数池)

Python 维护了一个小整数池,使得小整数在整个程序生命周期内共享相同的内存地址。

>>> a = 1
>>> b = 1
>>> id(a), id(b)  # 两者 ID 相同
(1402582080, 1402582080)

但对于较大的整数或对象,Python 不会自动共享内存:

>>> a = 1000
>>> b = 1000
>>> id(a), id(b)  # ID 不同
(1402582088, 1402582104)

总结

  1. 赋值(=) 仅创建新的变量名,不创建新对象。
  2. 浅复制(copy.copy()) 只复制最外层,嵌套对象仍然共享。
  3. 深复制(copy.deepcopy()) 递归复制所有层级,完全独立。
  4. Python 内存池 会优化小整数和字符串的内存使用。

形象的图讲解:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

👇🏻可通过点击下面——>关注本人运营 公众号👇🏻

🎯 深度交流 | 📌 标注“来自 CSDN”
🌟 解决问题,拓展人脉,共同成长!(非诚勿扰)
🚀 不止是交流,更是你的技术加速器!
评论 119
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤寒者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值