Python的深浅拷贝
相关概念
简单来说,一个对象所对应的东西包含但不限于下面两部分:
- 引用,也就是地址。
- 数据,也就是值。
还有两个概念是:
- 可变对象与不可变对象(对象值是否可修改)
- 容器对象与非容器对象(对象是否可以存放其它对象)
下面举几个重要对象类型的例子。
对象类型 | 可变 | 容器 |
---|---|---|
整数-int | 否 | 否 |
浮点-float | 否 | 否 |
字符串-str | 否 | 否 |
列表-list | 是 | 是 |
字典-dict | 是 | 是 |
元组-tuple | 否 | 是 |
从表中我们就可以看出元组(tuple)比较特殊,那也就意味着意味着在拷贝时也特殊。
深浅拷贝
通俗理解:
- 深拷贝就是拷贝的东西多,复制了引用,也复制了数据(开辟新内存)。
- 浅拷贝就是拷贝的东西少,复制了引用,没复制了数据(不开辟新内存)。
实践出真知(踩坑完毕)
引入Python自带的copy库
import copy
# 库中的对应函数,简单例子
a = 1 # 不可变非容器类型变量
b = copy.copy(a) # 浅拷贝
c = copy.deepcopy(a) # 深拷贝
# 通过查看内存地址判断深浅
print(id(a))
print(id(b))
print(id(c))
不可变非容器类型代码
import copy
a1 = 1 # 第一层是整数int------是不可变
a2 = 1.1 # 第一层是整数int------是不可变
a3 = 'bryan' # 第一层是整数int------是不可变
# 浅拷贝
b1 = copy.copy(a1)
b2 = copy.copy(a2)
b3 = copy.copy(a3)
# 深拷贝
c1 = copy.deepcopy(a1)
c2 = copy.deepcopy(a2)
c3 = copy.deepcopy(a3)
# 验证
print(id(a1),id(b1),id(c1))
print(id(a2),id(b2),id(c2))
print(id(a3),id(b3),id(c3))
可变容器类型代码
import copy
# 情况1 顶层是可变类型,下层(第二层及其以下层)都是不可变类型
a = [1, 2] # 第一层是列表list,第二层是整数int------是不可变类型(第二层)
# # 浅拷贝
b = copy.copy(a)
# # 深拷贝
c = copy.deepcopy(a)
# # 验证
print(id(a), id(b), id(c))
# 情况2 顶层是可变类型,下层存在可变类型
a1 = [1, 2]
a2 = [3, 4]
aa = [a1, a2] # 第一层是列表list, 第二层是列表list,第三层是整数int------存在可变类型(第二层)
print(id(a1), id(a2))
print(id(aa), id(aa[0]), id(aa[1]))
# # 浅拷贝
bb = copy.copy(aa )
# # 验证
print(id(bb), id(bb[0]), id(bb[1]))
# # 深拷贝
cc = copy.deepcopy(aa)
print(id(cc), id(cc[0]), i
# # 验证d(cc[1]))
不可变容器类型代码
import copy
# 情况1 顶层是不可变类型,下层都是不可变类型
a = (1, 2) # 第一层是元组tuple,第二层是整数int------是不可变类型(第二层)
# # 浅拷贝
b = copy.copy(a)
# # 深拷贝
c = copy.deepcopy(a)
# # 验证
print(id(a), id(b), id(c))
# 情况2 顶层是不可变类型,下层存在可变类型
a1 = [1, 2]
a2 = [3, 4]
aa = (a1, a2) # 第一层是元组tuple, 第二层是列表list,第三层是整数int------存在可变类型(第二层)
print(id(a1), id(a2))
print(id(aa), id(aa[0]), id(aa[1]))
# # 浅拷贝
bb = copy.copy(aa)
# # 验证
print(id(bb), id(bb[0]), id(bb[1]))
# # 深拷贝
cc = copy.deepcopy(aa)
# # 验证
print(id(cc), id(cc[0]), id(cc[1]))
# 顶层为可变容器型对象
a = [300, 400]
a1 = 500
b = (600, 700)
b1 = 800
c = (a, a1) # ([300, 400], 500)
c1 = [b, b1] # [(600, 700), 800]
d = [c, c1] # [([300, 400], 500), [(600, 700), 800]] 是一个最深具有四层的对象
e = copy.copy(d)
f = copy.deepcopy(d)
# 验证
print(id(a1), id(b1))
# >>> 140266444072368 140266444071664
print(id(a), id(b), id(a[0]), id(b[0]))
# >>> 140266442385736 140266443371016 140266444073008 140266444074192
print(id(c), id(c1), id(c[0]), id(c1[0]))
# >>> 140266443371272 140266443372936 140266442385736 140266443371016
print(id(d), id(e), id(f))
# >>> 140266442874760 140266442283912 140266443373448
print(id(d[0]), id(e[0]), id(f[0])) # 对应c
# >>> 140266443371272 140266443371272 140266442362568
print(id(d[1]), id(e[1]), id(f[1])) # 对应c1
# >>> 140266443372936 140266443372936 140266442295304
print(id(d[0][0]), id(e[0][0]), id(f[0][0])) # 对应c[0]
# >>> 140266442385736 140266442385736 140266442335880
print(id(d[1][0]), id(e[1][0]), id(f[1][0])) # 对应c1[0]
# >>> 140266443371016 140266443371016 140266443371016
print(id(d[0][0][0]), id(e[0][0][0]), id(f[0][0][0])) # 对应a[0]
# >>> 140266444073008 140266444073008 140266444073008
print(id(d[1][0][0]), id(e[1][0][0]), id(f[1][0][0])) # 对应b[0]
# >>> 140266444074192 140266444074192 140266444074192
# 顶层为不可变容器型对象
a1 = (1, 2)
a2 = [1, 2]
b1 = (3, 4)
b2 = [3, 4]
c1 = (5, 6)
c2 = [5, 6]
d1 = (7, 8)
d2 = [7, 8]
e1 = [a2, b2]
e2 = [a1, b2]
e3 = [a1, b1]
f1 = (c2, d2)
f2 = (c1, d2)
f3 = (c1, d1)
g1 = (e1, e2, e3, f1, f2, f3)
# g1 = [e1, e2, e3, f1, f2, f3]
print(g1)
j1 = copy.copy(g1)
k1 = copy.deepcopy(g1)
print(' | 原始 | 原始 | 浅拷贝 | 深拷贝 |')
print(' 第1层空空-不变-混可变:', id(g1), id(g1), id(j1), id(k1))
print(' 第2层不变-可变-全可变:', id(e1), id(g1[0]), id(j1[0]), id(k1[0]))
print(' 第2层不变-可变-混可变:', id(e2), id(g1[1]), id(j1[1]), id(k1[1]))
print(' 第2层不变-可变-全不变:', id(e3), id(g1[2]), id(j1[2]), id(k1[2]))
print(' 第2层不变-不变-全可变:', id(f1), id(g1[3]), id(j1[3]), id(k1[3]))
print(' 第2层不变-不变-混可变:', id(f2), id(g1[4]), id(j1[4]), id(k1[4]))
print(' 第2层不变-不变-全不变:', id(f3), id(g1[5]), id(j1[5]), id(k1[5]))
print(' 第3层不变-可变-全可变中可变-全不变:', id(a2), id(g1[0][0]), id(j1[0][0]), id(k1[0][0]))
print(' 第3层不变-可变-混可变中不变-全不变:', id(a1), id(g1[1][0]), id(j1[1][0]), id(k1[1][0]))
print(' 第3层不变-可变-混可变中可变-全不变:', id(b2), id(g1[1][1]), id(j1[1][1]), id(k1[1][1]))
print(' 第3层不变-可变-全不变中不变-全不变:', id(a1), id(g1[2][0]), id(j1[2][0]), id(k1[2][0]))
print(' 第3层不变-不变-全可变中可变-全不变:', id(c2), id(g1[3][0]), id(j1[3][0]), id(k1[3][0]))
print(' 第3层不变-不变-混可变中不变-全不变:', id(c1), id(g1[4][0]), id(j1[4][0]), id(k1[4][0]))
print(' 第3层不变-不变-混可变中可变-全不变:', id(d2), id(g1[4][1]), id(j1[4][1]), id(k1[4][1]))
print(' 第3层不变-不变-全不变中不变-全不变:', id(c1), id(g1[5][0]), id(j1[5][0]), id(k1[5][0]))
print('第4层不变-可变-全可变中可变-全不变中全不变-空空:', id(a2[0]), id(g1[0][0][0]), id(j1[0][0][0]), id(k1[0][0][0]))
print('第4层不变-可变-混可变中不变-全不变中全不变-空空:', id(a1[0]), id(g1[1][0][0]), id(j1[1][0][0]), id(k1[1][0][0]))
print('第4层不变-可变-混可变中可变-全不变中全不变-空空:', id(b2[0]), id(g1[1][1][0]), id(j1[1][1][0]), id(k1[1][1][0]))
print('第4层不变-可变-全不变中不变-全不变中全不变-空空:', id(a1[0]), id(g1[2][0][0]), id(j1[2][0][0]), id(k1[2][0][0]))
print('第4层不变-不变-全可变中可变-全不变中全不变-空空:', id(c2[0]), id(g1[3][0][0]), id(j1[3][0][0]), id(k1[3][0][0]))
print('第4层不变-不变-混可变中不变-全不变中全不变-空空:', id(c1[0]), id(g1[4][0][0]), id(j1[4][0][0]), id(k1[4][0][0]))
print('第4层不变-不变-混可变中可变-全不变中全不变-空空:', id(d2[0]), id(g1[4][1][0]), id(j1[4][1][0]), id(k1[4][1][0]))
print('第4层不变-不变-全不变中不变-全不变中全不变-空空:', id(c1[0]), id(g1[5][0][0]), id(j1[5][0][0]), id(k1[5][0][0]))
'''
不可变容器型对象为顶层
([[1, 2], [3, 4]], [(1, 2), [3, 4]], [(1, 2), (3, 4)], ([5, 6], [7, 8]), ((5, 6), [7, 8]), ((5, 6), (7, 8)))
| 原始 | 原始 | 浅拷贝 | 深拷贝 |
第1层空空-不变-混可变: 2586646017992 2586646017992 2586646017992 2586646019144
第2层不变-可变-全可变: 2586646001544 2586646001544 2586646001544 2586646056584
第2层不变-可变-混可变: 2586642499912 2586642499912 2586642499912 2586645922440
第2层不变-可变-全不变: 2586646055048 2586646055048 2586646055048 2586646118536
第2层不变-不变-全可变: 2586646268040 2586646268040 2586646268040 2586646267592
第2层不变-不变-混可变: 2586646267976 2586646267976 2586646267976 2586646267720
第2层不变-不变-全不变: 2586646267912 2586646267912 2586646267912 2586646267912
第3层不变-可变-全可变中可变-全不变: 2586645883336 2586645883336 2586645883336 2586645985480
第3层不变-可变-混可变中不变-全不变: 2586646121864 2586646121864 2586646121864 2586646121864
第3层不变-可变-混可变中可变-全不变: 2586646221192 2586646221192 2586646221192 2586646119240
第3层不变-可变-全不变中不变-全不变: 2586646121864 2586646121864 2586646121864 2586646121864
第3层不变-不变-全可变中可变-全不变: 2586642963528 2586642963528 2586642963528 2586646270216
第3层不变-不变-混可变中不变-全不变: 2586646223240 2586646223240 2586646223240 2586646223240
第3层不变-不变-混可变中可变-全不变: 2586646221832 2586646221832 2586646221832 2586646270472
第3层不变-不变-全不变中不变-全不变: 2586646223240 2586646223240 2586646223240 2586646223240
第4层不变-可变-全可变中可变-全不变中全不变-空空: 140711794418064 140711794418064 140711794418064 140711794418064
第4层不变-可变-混可变中不变-全不变中全不变-空空: 140711794418064 140711794418064 140711794418064 140711794418064
第4层不变-可变-混可变中可变-全不变中全不变-空空: 140711794418128 140711794418128 140711794418128 140711794418128
第4层不变-可变-全不变中不变-全不变中全不变-空空: 140711794418064 140711794418064 140711794418064 140711794418064
第4层不变-不变-全可变中可变-全不变中全不变-空空: 140711794418192 140711794418192 140711794418192 140711794418192
第4层不变-不变-混可变中不变-全不变中全不变-空空: 140711794418192 140711794418192 140711794418192 140711794418192
第4层不变-不变-混可变中可变-全不变中全不变-空空: 140711794418256 140711794418256 140711794418256 140711794418256
第4层不变-不变-全不变中不变-全不变中全不变-空空: 140711794418192 140711794418192 140711794418192 140711794418192
'''
'''
可变容器型对象为顶层
[[[1, 2], [3, 4]], [(1, 2), [3, 4]], [(1, 2), (3, 4)], ([5, 6], [7, 8]), ((5, 6), [7, 8]), ((5, 6), (7, 8))]
| 原始 | 原始 | 浅拷贝 | 深拷贝 |
第1层空空-可变-混可变: 2386590517384 2386590517384 2386603573768 2386603707848
第2层可变-可变-全可变: 2386593509064 2386593509064 2386593509064 2386603636744
第2层可变-可变-混可变: 2386603648712 2386603648712 2386603648712 2386603770568
第2层可变-可变-全不变: 2386603707272 2386603707272 2386603707272 2386603772872
第2层可变-不变-全可变: 2386603919048 2386603919048 2386603919048 2386603918664
第2层可变-不变-混可变: 2386603918984 2386603918984 2386603918984 2386603918792
第2层可变-不变-全不变: 2386603918920 2386603918920 2386603918920 2386603918920
第3层可变-可变-全可变中可变-全不变: 2386603534664 2386603534664 2386603534664 2386603636872
第3层可变-可变-混可变中不变-全不变: 2386603773000 2386603773000 2386603773000 2386603773000
第3层可变-可变-混可变中可变-全不变: 2386603874184 2386603874184 2386603874184 2386585871560
第3层可变-可变-全不变中不变-全不变: 2386603773000 2386603773000 2386603773000 2386603773000
第3层可变-不变-全可变中可变-全不变: 2386603773640 2386603773640 2386603773640 2386603921352
第3层可变-不变-混可变中不变-全不变: 2386603462024 2386603462024 2386603462024 2386603462024
第3层可变-不变-混可变中可变-全不变: 2386603770248 2386603770248 2386603770248 2386603921224
第3层可变-不变-全不变中不变-全不变: 2386603462024 2386603462024 2386603462024 2386603462024
第4层可变-可变-全可变中可变-全不变中全不变-空空: 140711794418064 140711794418064 140711794418064 140711794418064
第4层可变-可变-混可变中不变-全不变中全不变-空空: 140711794418064 140711794418064 140711794418064 140711794418064
第4层可变-可变-混可变中可变-全不变中全不变-空空: 140711794418128 140711794418128 140711794418128 140711794418128
第4层可变-可变-全不变中不变-全不变中全不变-空空: 140711794418064 140711794418064 140711794418064 140711794418064
第4层可变-不变-全可变中可变-全不变中全不变-空空: 140711794418192 140711794418192 140711794418192 140711794418192
第4层可变-不变-混可变中不变-全不变中全不变-空空: 140711794418192 140711794418192 140711794418192 140711794418192
第4层可变-不变-混可变中可变-全不变中全不变-空空: 140711794418256 140711794418256 140711794418256 140711794418256
第4层可变-不变-全不变中不变-全不变中全不变-空空: 140711794418192 140711794418192 140711794418192 140711794418192
'''
总结
顶层可为任意对象类型
底层只可是为数字和字符对象类型
不可变非容器型对象为顶层(只有一层所以也为底层):
- copy.copy():具有相同引用,不开辟新内存。
- copy.deepcopy():具有相同引用,不开辟新内存。
可变容器型对象为顶层(可嵌套多层):
- copy.copy():只有顶层具有不同引用,开辟新内存;剩下所有层具有相同引用,不开辟新内存。
- copy.deepcopy():在嵌套路径中从底层开始连续的具有不可变类型的所有层中的最顶层(以下简称顶不变层)之上的层的对象都具有不同引用,开辟新内存;顶不变层以下的层及其自身的对象具有相同引用,不开辟新内存。
不可变容器型对象为顶层(可嵌套多层):
- copy.copy():具有相同引用,不开辟新内存。
- copy.deepcopy():只要嵌套路径中的对象存在可变类型,在具有可变类型的所有层中的最底层(以下简称底变层)之上的层都具有不同引用,开辟新内存;底变层以下的层及其本身具有相同引用,不开辟新内存。
注:此文章仅为作者拙见,如有错误,欢迎读者批评指正 !!!原创文章转载请注明,谢谢。