在开始我们要先了解可变对象和不可变对象,所谓的可变对象就是即使我们对对象的值进行修改,对象所指向的地址也不会改变,由此类推,不可变对象就是一旦我们对对象的值进行修改,对象所指向的地址就会发生改变。下面我们先来看几个例子:
list1 = [1, 2, 3, [4, 5, 6]]
print(f"id_list1[0]:{id(list1[0])},id_list1[3]:{id(list1[3])}")
list1[0] = 9
list1[3].append(7)
print(list1)
print(f"id_list1[0]{id(list1[0])},id_list1[3]{id(list1[3])}")
id_list1[0]:140714489245952,id_list1[3]:2631977918984
[9, 2, 3, [4, 5, 6, 7]]
id_list1[0]140714489246208,id_list1[3]2631977918984
我们把注意力放到list1列表里的对象上,我们可以看出list1[0] (内存地址变化)是不可变对象,list1[3] (内存地址不变)作为一个列表是可变对象。
我们在遇到深拷贝和浅拷贝的时候,需要注意的也是这些问题,下面以实例讲解:
list1 = [1, 2, 3, [4, 5, 6]]
list2=list1 #赋值引用
list3=list1.copy() #浅拷贝
list4=copy.deepcopy(list1) #深拷贝
print(f"list1:{list1},id_list1:{id(list1)},id_list1[3]:{id(list1[3])}")
print(f"list2:{list2},id_list2:{id(list2)},id_list2[3]:{id(list2[3])}")
print(f"list3:{list3},id_list3:{id(list3)},id_list3[3]:{id(list3[3])}")
print(f"list4:{list4},id_list4:{id(list4)},id_list4[3]:{id(list4[3])}")
list1.append(7) #对列表list1进行添加
list1[3].append(8) #对列表list1里的[4,5,6]进行添加
print(f"list1:{list1},id_list1:{id(list1)},id_list1[3]:{id(list1[3])}")
print(f"list2:{list2},id_list2:{id(list2)},id_list2[3]:{id(list2[3])}")
print(f"list3:{list3},id_list3:{id(list3)},id_list3[3]:{id(list3[3])}")
print(f"list4:{list4},id_list4:{id(list4)},id_list4[3]:{id(list4[3])}")
结果如下:
list1:[1, 2, 3, [4, 5, 6]],id_list1:1749900126344,id_list1[3]:1749900127368
list2:[1, 2, 3, [4, 5, 6]],id_list2:1749900126344,id_list2[3]:1749900127368
list3:[1, 2, 3, [4, 5, 6]],id_list3:1749900124936,id_list3[3]:1749900127368
list4:[1, 2, 3, [4, 5, 6]],id_list4:1749901280456,id_list4[3]:1749900126600
list1:[1, 2, 3, [4, 5, 6, 8], 7],id_list1:1749900126344,id_list1[3]:1749900127368
list2:[1, 2, 3, [4, 5, 6, 8], 7],id_list2:1749900126344,id_list2[3]:1749900127368
list3:[1, 2, 3, [4, 5, 6, 8]],id_list3:1749900124936,id_list3[3]:1749900127368
list4:[1, 2, 3, [4, 5, 6]],id_list4:1749901280456,id_list4[3]:1749900126600
由于python是动态语言,我们在list2=list1的时候并list2没有新开辟一个地址空间来进行存储,而是引用了list1的地址空间,也正因为这样我们在对list1进行修改的时候,list2也会相应的改变。
接下来就是浅拷贝了,既然是浅拷贝,顾名思义,拷贝的应该不是特别干脆,我们将list1与list3前后对比可以发现,list1和list3的内存地址相同,list1[3] 和 list3[3] 内存地址相同,浅拷贝在拷贝的时候除了拷贝了不可变对象的内存地址,在拷贝 list1[3] 的时候把[4,5,6]作为一个可变对象并将它的内存地址拷贝下来,也因此在后来 list1[3] 添加元素后,对应的我们在输出 list3[3] 的时候计算机去访问的是之前[4,5,6]这个对象所在的地址,结果现在这个地址又增加了一个8 所以输出了[4,5,6,8],而7只是添加给了list1,所以list3 没有7。
深拷贝就比较简单了,就是拷贝的很彻底,就是相当于另外一个空间里就存了一份,跟之前的一点关系也没有,所以之前的无论如何变化,深拷贝的都不会发生变化。