Python中的浅拷贝和深拷贝

浅拷贝,深拷贝,老生常谈了,写下来,希望记住

在编程的时候经常会遇到拷贝问题,其中有浅拷贝与深拷贝之分,关乎之后的数据变动,需要分清。

拷贝

浅拷贝:对象地址的拷贝

深拷贝:对象资源的拷贝

我们申请变量并进行赋值的时候,

首先是在内存开辟一个空间,用于存放我们定义的值,而后再将存放的地址赋予我们的变量。

所以存在对象资源和地址拷贝的区别。

Python中的变量赋值

在Python中,

修改不可变对象(str、 tuple)需要开辟新的空间

修改可变对象(list、set.dict)时不需要开辟新的空间

具体实验如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
a = 'bb'
print(a,id(a))
a = 'bbb'
print(a,id(a))
b = [1,2]
print(b,id(b))
b.append(3)
print(b,id(b))
b += [4]
print(b,id(b))
b = [1,2,3,4,5]
print(b,id(b))
Output:
bb 1685542671392
bbb 1685535539248
[1, 2] 1685601411400
[1, 2, 3] 1685601411400
[1, 2, 3, 4] 1685601411400
[1, 2, 3, 4, 5] 1685605110920

当a修改字符串后,指向的是新的’bbb’的空间,而b如果是通过增加的方式,地址是不会变的,但是如果是通过整体赋值的方式,还是会改变的

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
a = ['hello',[1,2,3]]
b = a[:]
print("Initial a,b")
print(a)
print( [ id(x) for x in a] )
print(b)
print( [ id(x)for x in b] )
a[0] = "world-a"
a[1].append(4)
print("Change a")
print(a)
print( [ id(x) for x in a] )
print(b)
print( [ id(x)for x in b] )
b[0] = 'world-b'
b[1].append(5)
print("Change b")
print(a)
print( [ id(x) for x in a] )
print(b)
print( [ id(x)for x in b] )
Output:
Initial a,b
['hello', [1, 2, 3]]
[1685595499688, 1685596629704]
['hello', [1, 2, 3]]
[1685595499688, 1685596629704]
Change a
['world-a', [1, 2, 3, 4]]
[1685597381720, 1685596629704]
['hello', [1, 2, 3, 4]]
[1685595499688, 1685596629704]
Change b
['world-a', [1, 2, 3, 4, 5]]
[1685597381720, 1685596629704]
['world-b', [1, 2, 3, 4, 5]]
[1685597383848, 1685596629704]

如果是通过=这种方式,是浅拷贝,可以发现:

对于不可变量,即a和b中的第一个元素,a或者b修改后,会各自修改,因为a修改后,指向了新的地址,而b指向的还是旧地址,所以b没有变动,同样的,咱们改了b,a也不会变,

对于可变量,即a和b中的列表,a或者b修改后,会同步修改,因为二者指向的都是一个地址,那么动一发而牵全身

深拷贝:

完全拷贝了一个副本,对象内部元素地址都不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> from copy import deepcopy
>>> a=['hello',[1,2,3]]
>>> b=deepcopy(a)
>>> [id(x) for x in a]
[55792504, 55645000]
>>> [id(x) for x in b]
[55792504, 58338824]
>>> a[0]='world'
>>> a[1].append(4)
>>>
>>> print(a)
['world', [1, 2, 3, 4]]
>>> print(b)
['hello', [1, 2, 3]]

显而易见,一开始我们拷贝的时候,除了不可变量的地址是相同的,可变量的地址就已经不同的,各过各的,分裂地更”深刻”

参考:

谈谈python中的深拷贝和浅拷贝

0%