0%

python中的赋值,浅拷贝与深拷贝

在写python项目的时候,遇见一个python拷贝对象的坑,在此总结记录一下python中的赋值,浅拷贝与深拷贝。

不可变数据类型:数字,字符串和元组

在python中,不可变对象的赋值,浅拷贝,深拷贝都指向同一个地址,三者没有区别:

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
>>> n1 = 1
>>> n2 = n1
>>> n3 = copy.copy(n1)
>>> n4 = copy.deepcopy(n1)
>>> n1 = 2
>>> print(n1)
2
>>> print(n2)
1
>>> print(n3)
1
>>> print(n4)
1
>>> print(id(n1))
4503975584
>>> print(id(n2))
4503975552
>>> print(id(n3))
4503975552
>>> print(id(n4))
4503975552
>>> s = (1,2,3)
>>> s1 = s
>>> s2 = copy.copy(s)
>>> s3 = copy.deepcopy(s)
>>> s = (1,2)
>>> print(s)
(1, 2)
>>> print(s1)
(1, 2, 3)
>>> print(s2)
(1, 2, 3)
>>> print(s3)
(1, 2, 3)
>>> print(id(s))
4508458760
>>> print(id(s1))
4508464256
>>> print(id(s2))
4508464256
>>> print(id(s3))
4508464256

对于不可变类型,当修改的时候会替换旧的对象,(进行新的内存分配)产生一个新的地址

元组对象比较特殊

元组是不可变对象,但是元素可以是可变对象,还是可以改变元组的元素 。

当元组元素是不可变类型时,赋值,浅拷贝,深拷贝都指向同一个地址。

当元组元素是可变类型时,赋值和浅拷贝指向同一地址,深拷贝会另辟空间。

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
>>> sf = ([1,2],[3,4])
>>> sf1 = sf
>>> import copy
>>> sf2 = copy.copy(sf)
>>> sf3 = copy.deepcopy(sf)
>>> print(id(sf))
4387941064
>>> print(id(sf1))
4387941064
>>> print(id(sf2))
4387941064
>>> print(id(sf3))
4387952776
>>> sf[1].append(5)
>>> print(id(sf))
4387941064
===================================
>>> sd = (1,2)
>>> sd1 = sd
>>> sd2 = copy.copy(sd)
>>> sd3 = copy.deepcopy(sd)
>>> print(id(sd))
4387950856
>>> print(id(sd1))
4387950856
>>> print(id(sd2))
4387950856
>>> print(id(sd3))
4387950856

可变数据类型:列表,字典和集合

一图胜千言:

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
>>> import copy
>>> a = [1,2,3,[1,2,3]]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(4)
>>> a[3].append(4)
>>> print(a)
[1, 2, 3, [1, 2, 3, 4], 4]
>>> print(b)
[1, 2, 3, [1, 2, 3, 4], 4]
>>> print(c)
[1, 2, 3, [1, 2, 3, 4]]
>>> print(d)
[1, 2, 3, [1, 2, 3]]
>>> a_dict = {'1':1,'2':2,'3':{'1':1,'2':2,'3':3}}
>>> b_dict = a_dict
>>> c_dict = copy.copy(a_dict)
>>> d_dict = copy.deepcopy(a_dict)
>>> a_dict['4'] = 4
>>> a_dict['3']['4'] = 4
>>> print(a_dict)
{'1': 1, '2': 2, '3': {'1': 1, '2': 2, '3': 3, '4': 4}, '4': 4}
>>> print(b_dict)
{'1': 1, '2': 2, '3': {'1': 1, '2': 2, '3': 3, '4': 4}, '4': 4}
>>> print(c_dict)
{'1': 1, '2': 2, '3': {'1': 1, '2': 2, '3': 3, '4': 4}}
>>> print(d_dict)
{'1': 1, '2': 2, '3': {'1': 1, '2': 2, '3': 3}}

注意,集合的元素不能为可变类型,所以对于集合浅拷贝和深拷贝没有区别。

总结

对于可变类型对象,赋值只是增加了一个对象的引用,它们指向内存中的同一个对象;浅拷贝会开辟新内存将对象拷贝一份,但是不会拷贝子对象;深拷贝会开辟新内存将对象拷贝后,连带子对象也拷贝,与原对象完全独立。