浅谈赋值, 浅复制与深复制的区别

赋值,浅复制,深复制的区别

赋值

首先是赋值:赋值并不会产生一个独立的对象单独存在,可以看作是给某对象贴上一个新标签

看下下面这段代码

1
2
3
4
a = [1, 2, 3, 4, 5]
b = a
a = [2, 3, 4, 5, 6]
print(b)

运行结果是

1
[1, 2, 3, 4, 5]

可以看到令b = a后,给a重新赋值,b并没有改变

再看下面这段代码

1
2
3
4
a = [1, 2, 3, 4, 5]
b = a
a[0] = 2
print(b)

运行结果是

1
[2, 2, 3, 4, 5]

这里可以看到改变a[0]的值后,b[0]也发生了改变

怎么理解这个呢,得先了解python的数据存储方式


python的数据存储方式

python的数据存储方式与其他OOP语言不同。它与其说是把某个值赋给变量,不如说是给变量建立了一个到具体值的引用

以上面的两段代码为例,先看第一段代码

a = [1, 2, 3, 4, 5],这个语句可以看成是将a这个标签贴到了[1,2,3,4,5]这个列表上,然后b = a,可以看作又将b这个标签贴到了[1,2,3,4,5]这个列表上,之后a = [2,3,4,5,6],便是将a这个标签从[1,2,3,4,5]这个列表上拿下来,贴到了一个新列表上,所以实际上b指向的列表并未发生变化

再看第二段代码

同样是将a,b这两个标签先后贴到[1,2,3,4,5]这个列表上,然后a[0] = 2,这个语句是真正改变了[1,2,3,4,5]这个列表中的元素,而b这个标签是指向该列表的,于是相应的b[0]也发生了改变


深复制

直接给出结论,深复制是产生一个独立于原对象的新对象,新对象与原对象之间不会互相影响

可以看下面这个列子

1
2
3
4
5
6
import copy

a = [1, 2, 3, 4, 5]
b = copy.deepcopy(a)
a[0] = 2
print(b)

运行结果是

1
[1, 2, 3, 4, 5]

浅复制

浅复制要分两种情况进行讨论:

  1. 当浅复制的对象是不可变对象(数值,字符串,元组)时和“等于赋值”的情况一样,对象的id值与浅复制原来的对象相同

  2. 当浅复制的对象是可变对象(列表,集合和字典)时,又分为两种情况:

    第一种情况: 浅复制的对象中无复杂子对象时,新对象与浅复制原来的对象不会互相影响,id值不同

    第二种情况: 浅复制的对象中有复杂子对象时,如果不改变其中复杂子对象,浅复制的值改变并不会影响原对象的值。但是改变其中的复杂子对象,则浅复制的值改变会影响原对象的值

看下面两个例子

1
2
3
4
5
6
import copy

a = [[1,2,3], 2, 3, 4, 5]
b = copy.copy(a)
b[1] = 3
print(a)

结果是

1
[[1, 2, 3], 2, 3, 4, 5]

可以看到改变b[1]并没有影响a的值,再看第二个例子

1
2
3
4
5
6
import copy

a = [[1,2,3], 2, 3, 4, 5]
b = copy.copy(a)
b[0][0] = 2
print(a)

可以看到改变b[0] [0]的值影响了a的值

参考Python—copy()、deepcopy()与赋值的区别