Z.S.K.'s Records

python中的copy及deepcopy

今天因为项目中遇到了拷贝,调试结果突然跟自己之前对拷贝相关的认知有点出路,还真跟自己想的有点不一样,看来错了很久,赶紧补下课,记录一下.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import copy
#使用copy需要导入
a = [1,2,[3,4]]
b = a
#直接赋值语句,相当于给a添加了一个引用,其中任何一个变化,另一个都会同步变化
#id(a)跟id(b) 输入相同,可以使用a is b 返回 True
id(a),id(b)
#输出 (50311880, 50311880)
a is b
#输出 True
c = copy.copy(a)
#这里对a进行浅拷贝
print(c)
#输出[1,2,[3,4]]
id(a),id(c)
#输出 (50311880, 50232904)
a is c
#输出 False
#从这里可以看出,a,c指向的不是一个变量,父对象指的就是a跟c
#那如果看子对象呢,子对象指的就是a里面的 [4,5]
#先对a
for x in a:
id(x)
#输出
#2004268720
#2004268752
#50311944

#再对c
for x in c:
id(x)
#输出
#2004268720
#2004268752
#50311944

#从上面可以看出,a跟c虽然指向不同,也就是说父对象不同,但是两者指向的子对象却是一样的,对子对象中的[4,5]也是一样的结果

d = copy.deepcopy(a)
#对a进行深拷贝
print(d)
#输出[1,2,[3,4]]
id(a),id(d)
#输出 (50311880, 50412168)
a is d
#输出 False

for x in d:
id(x)
#输出
#2004268720
#2004268752
#50412040
#从这里可以看出 d跟a,后面的子对象[4,5]指向不一样,而c跟a的[4,5]指向是一样的

for x in d[2]:
id(x)
#输出
#2004268784
#2004268816
#这跟
for x in a[2]:
id(x)
for x in c[2]:
id(x)
#这三者的结果是一样的

#如果这时我修改a的值,再来看看c,d的变化
#追加一个值
a.append([5,6])
print(a)
#输出 [1,2,[3,4],[5,6]]
print(b)
#输出 [1,2,[3,4],[5,6]]
print(c)
#输出 [1,2,[3,4]]
print(d)
#输出 [1,2,[3,4]]
#可以看出 c跟d都没有变化

#如果我们修改a的[4,5]这个子对象
a[2].append('0')
print(a)
#输出 [1,2,[3,4,0]]
print(b)
#输出 [1,2,[3,4,0]]
print(c)
#输出 [1,2,[3,4,0]]
print(d)
#输出 [1,2,[3,4]]
#可以看出 c跟a变化了,d没有变化,为何c会跟着变化?这就是copy跟deepcopy的区别

对于不可变对象(int,string),copy跟deepcopy没有任何区别,使用id也是相同的值,但如果是复杂对象(那些对象中可包含子对象的嵌套对象,如list,tuple)等,就有区别了.

对于包含子对象的复杂对象,copy并未从原对象中真正独立出来,也就是说,如果你改变原 object 的子 list 中的一个元素,你的 copy 就会跟着一起变.这跟我们直觉上对「复制」的理解不同.

而deepcopy则是真正的跟原对象没有关系了,对原对象的任何变化都不会影响deepcopy.

代码中如果我们需要拷贝一个对象,且这个对象不受原对象的改变而改变,直接使用deepcopy.

参考文章:

转载请注明原作者: 周淑科(https://izsk.me)


 wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?