原理:不可变对象是值传递;可变对象是引用传递。
浅拷贝
所属模块:copy.copy()。
import copy # 导包
list1 = ['w', 20, 10, ['d', 21, 11]] # 列表中包括可变对象和不可变对象
list2 = list1.copy() # 浅拷贝
list3 = copy.copy(list1) # 浅拷贝,和上面的浅拷贝一样
print(id(list1),id(list3)) # 两者内存地址不一样
print(id(list1[0]), id(list3[0])) # 不可变对象的内存地址一样
print(id(list1[3]), id(list3[3])) # 可变对象的内存地址一样
list3[3].append('f')
print(list1, list3) # 两者的第四个元素中都出现了'f',因为可变对象在浅拷贝时是引用传递,在拷贝过程中可变对象的地址不改变。
list3[0] = 're'
print(list1, list3) # 结果仅有list3自己的'w'改变成了're',因为不可变对象在浅拷贝中是值传递,改变后该元素的存储地址也变了。
总结:
1、浅拷贝后list3的地址与list1的地址不同,但是它们内部数据的存储地址是一样的;
2、在改变list3中的可变对象时,因为是引用传递,所以list1、list3都进行了修改;
3、在改变list3中的不可变对象时,因为是值传递,所以只在list3中进行了修改。
深拷贝
所属模块:copy.deepcopy()。
import copy
list1 = ['w', 20, 10, ['d', 21, 11]] # 列表中包括可对对象和不可变对象
list2 = copy.deepcopy(list1) # 深拷贝
print(id(list1), id(list2)) # 两者的内存地址不一样
print(id(list1[0]), id(list2[0])) # 不可变对象的存储地址相同
print(id(list1[3]), id(list2[3])) # 可变对象的存储地址不相同
list2[3].append('f')
print(list1, list2) # 仅list2的第四个嵌套列表中出现了'f',因为可变对象在深拷贝时是值传递,在拷贝时可变对象的存储地址就已经变了。
list2[0] = 're'
print(list1, list2) # 仅list2自己的'w'改变成了're',因为不可变对象在深拷贝中是值传递,改变后该元素的存储地址也变了。
总结:
1、深拷贝后list2的地址与list1的地址不同;
2、它们内部可变对象的地址拷贝时改变,不可变对象的地址拷贝时不变;所以两者都类似于值传递,list2修改任何元素都不会引起list1中元素的改变。