深拷贝和浅拷贝

深浅拷贝

介绍

首先需要理解python中有6种标准数据类型,他们又分为可变类型和不可变类型。

不可变:Number 数字 、String 字符串、Tuple 元组

可变:List列表、Dictionary字典、Set集合

深拷贝和浅拷贝都是对象的拷贝,都会生成一个看起来相同的对象,他们本质的区别是拷贝出来的对象的地址是否和原对象一样。

深拷贝

拷贝了一份与原对象不同地址的对象,修改对象中的任何值,都不会改变深拷贝对象。

浅拷贝

对原对象值进行拷贝,地址仍然指向原对象的地址,原对象的值发生变化,拷贝对象的值也会随之改变。

例子

# 浅拷贝单层不可变对象
import copy

a = 1
b = copy.copy(a)
print(id(a))  # 140730849826576
print(id(b))  # 140730849826576


# 深拷贝单层不可变量对象
import copy

a = 1
b = copy.deepcopy(a)
print(id(a))  # 140730849826576
print(id(b))  # 140730849826576
# 结论:当拷贝单层不可变对象时,深拷贝与浅拷贝效果一样,都是同一个地址
# 浅拷贝单层可变对象
import copy

a = [1, 2, 3, 4]
b = copy.copy(a)
print(id(a))  # 1561756601856
print(id(b))  # 1561756584576

# 深拷贝单层可变量对象
import copy

a = [1, 2, 3, 4]
b = copy.deepcopy(a)
print(id(a))  # 2269025963648
print(id(b))  # 2269025946368
# 结论:当拷贝单层可变对象时,深拷贝与浅拷贝效果一样,地址都发生了改变,说明不再是引用同一个地址数据,而是生成了新的对象。
  • 深拷贝和浅拷贝对于单层的数据对象时,效果时一样的,因为浅拷贝就是拷贝一层,而深拷贝是递归拷贝到最后一层。
# 浅拷贝两层可变对象
import copy

a = [[5, 6, 7], 2, 3, 4]
b = copy.copy(a)
print(id(a))  # 2535199754880
print(id(b))  # 2535199770816
print(id(a[0]))  # 2535199772160
print(id(b[0]))  # 2535199772160
a[0][0] = 9
print(b)  # [[9, 6, 7], 2, 3, 4]

# 深拷贝两层可变对象
import copy

a = [[5, 6, 7], 2, 3, 4]
b = copy.deepcopy(a)
print(id(a))  # 2267261131136
print(id(b))  # 2267261147072
print(id(a[0]))  # 2267261148416
print(id(b[0]))  # 2267261147840
a[0] = [8, 9, 10]
print(b[0])  # [5, 6, 7]

# 结论:在拷贝两层可变对象时,深浅拷贝都生成了一个对象,但是浅拷贝只拷贝了一层,里面的只是引用的,修改了里面可变对象的值,拷贝出来的对象也会跟着改变。对于深拷贝来说,由于是递归拷贝,所以里面一样是生成了新的对象,修改后拷贝出的对象不会跟着改变。
# 浅拷贝两层内层不可变对象
import copy

a = [(5, 6, 7), 2, 3, 4]
b = copy.copy(a)
print(id(a))  # 1547471195200
print(id(b))  # 1547471177920
print(id(a[0]))  # 1547423597632
print(id(b[0]))  # 1547423597632

# 深拷贝两层内层不可变对象
import copy

a = [(5, 6, 7), 2, 3, 4]
b = copy.deepcopy(a)
print(id(a))  # 2252729126272
print(id(b))  # 2252729108992
print(id(a[0]))  # 2254828946368
print(id(b[0]))  # 2254828946368

# 结论:都生成了新的对象,由于里面都是不可变对象,因此现象是一样的。深拷贝也相当于只拷贝了一层。
# 浅拷贝两层不可变内部可变对象
import copy

a = ([5, 6, 7], 2, 3, 4)
b = copy.copy(a)
print(id(a))  # 2420930980496
print(id(b))  # 2420930980496
print(id(a[0]))  # 2420977404992
print(id(b[0]))  # 2420977404992
a[0][0] = 9
print(b)  # ([9, 6, 7], 2, 3, 4)

# 深拷贝两层不可变内部可变对象
import copy

a = ([5, 6, 7], 2, 3, 4)
b = copy.deepcopy(a)
print(id(a))  # 1586605599456
print(id(b))  # 1586605896304
print(id(a[0]))  # 1586652089728
print(id(b[0]))  # 1586652088384
a[0][0] = 9
print(b)  # ([5, 6, 7], 2, 3, 4)
# 结论:浅拷贝就相当于单层不可变对象一样,无论外层和内层地址都没有变,因此修改内部元素时,拷贝后的对象也会发生改变。深拷贝无论内层和外层都生成了一个新的对象,地址都发生了改变,修改内部元素时,拷贝出来的对象不会跟着改变。
# 浅拷贝两层不可变对象
import copy

a = ((5, 6, 7), 2, 3, 4)
b = copy.copy(a)
print(id(a))  # 1590866961968
print(id(b))  # 1590866961968
print(id(a[0]))  # 1590869967488
print(id(b[0]))  # 1590869967488

# 深拷贝两层不可变对象
import copy

a = ((5, 6, 7), 2, 3, 4)
b = copy.deepcopy(a)
print(id(a))  # 2024255350320
print(id(b))  # 2024255350320
print(id(a[0]))  # 2024257307520
print(id(b[0]))  # 2024257307520
# 结论:深浅拷贝两层不可变对象内外两层地址都没改变,浅拷贝只拷贝第一层,由于是不可变对象,所以地址没有改变。深拷贝虽然是递归拷贝,但是由于不可变对象里面没有可变对象,所以停止了拷贝,也是引用的同一地址。
# 浅拷贝多层
import copy

a = [([0, 0, 0, 0], 6, 7), 2, 3, 4]
b = copy.copy(a)
print(id(a))  # 1694468823872
print(id(b))  # 1694468839808
print(id(a[0]))  # 1694468166080
print(id(b[0]))  # 1694468166080
a[0][0][0] = 9
print(b)  # [([9, 0, 0, 0], 6, 7), 2, 3, 4]

# 深拷贝多层
import copy

a = [([0, 0, 0, 0], 6, 7), 2, 3, 4]
b = copy.deepcopy(a)
print(id(a))  # 2240036821888
print(id(b))  # 2240036837824
print(id(a[0]))  # 2240036164160
print(id(b[0]))  # 2240036864256
a[0][0][0] = 9
print(b)  # [([0, 0, 0, 0], 6, 7), 2, 3, 4]

浅拷贝只拷贝第一层,深拷贝递归拷贝到内部没有可变对象。

可变类型:
浅拷贝和深拷贝只要最外层是可变类型都会生成新的对象
[] 或者{}, 浅拷贝和深拷贝都会生成新的对象
[[],[]]列表的嵌套,可变类型嵌套了可变类型,浅拷贝, 只拷贝最外层,会生成新的对象, 内层是引用。深拷贝 外层和内层都会进行拷贝,都是全新的对象, 都有独立的存储空间
不可变类型:
最外层是不可变类型, 浅拷贝就一定是引用
([],[]), copy浅拷贝, 只会拷贝最外层,内层只是引用, 但是最外层是不可变,拷贝之后毫无意义,仅仅是引用关系, deepcopy,从外层到内层都会拷贝,内层是可变,为了达到和原来的数据完全隔离, 会生成全新的对象
((),()) 完全不可变, 拷贝了之后如果生成新的数据也无法修改, 所以不管深拷贝还是浅拷贝都是引用
((),[]) 外层不可变,但是内层有一个是可变, copy依然是引用, deepcopy,会生成新的对象,内层的不可变类型是引用, 可变类型会生成新的对象

posted @   雨快停了  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示