python:由深浅拷贝谈到变量值的核心区别
Demo
import copy
a = [1, 2, 3]
b = [1, 2, 3]
c = a.copy()
a.append(4)
print(id(a), a)
print(id(b), b)
print(id(c), c)
d = [1, 2, 3, {"测试":"123"}]
e = d.copy()
f = copy.deepcopy(d)
e[3]["测试"] = "demo"
print(id(d), d)
print(id(e), e)
print(id(f), f)
2980371881920 [1, 2, 3, 4]
2980371734784 [1, 2, 3]
2980371881088 [1, 2, 3]
2980371880832 [1, 2, 3, {'测试': 'demo'}]
2980371881728 [1, 2, 3, {'测试': 'demo'}]
2980371881664 [1, 2, 3, {'测试': '123'}]
浅拷贝
首先,浅拷贝,将列表中所有内容复制一遍,赋值给新的列表对象,这时候生成的新的列表对象,所以id()看到的内存地址是不同的。新列表中所有元素存放的地址,和原列表所有元素存放地址,是相同的,因为两个列表中的内容也是相同的。
问1:为什么a列表新增元素,c列表不会改变?
答1:因为a c列表是不同的对象,两个没有关系。
问2:为什么a列表更新表格中的已有内容,c列表页不会改变?
答2:因为a c列表存放的,都是字符串或者数字,每次修改其实是返回一个新的内容,也可以说是直接把元素指向新的地址。a修改只会影响a的列表。c列表的元素地址还是指向原来的地址。
问3:为什么d列表修改以后,浅拷贝的e列表会跟着修改,而深拷贝的f列表不会跟着修改?
答3:同答2中所说,浅拷贝copy只把列表中的元素或者说元素保存的内存地址复制。但是这里d列表中修改的是字典对象,字典对象不像字符串或者数字修改后返回一个新的对象,字典对象修改后只修改内容,对象还是原来那个对象,地址还是那个地址,因为浅拷贝的e列表根据拷贝的地址还是找到了修改后的字典对象。
深拷贝
那么为什么深拷贝不同呢?因为深拷贝是直接深层遍历了d列表中所有元素,是直接把字典里所有的内容也复制走了,这里新列表存放的字典也是一个新的对象。因此修改d列表的字典对象,不会影响e列表。
需要注意的是,这种情况不止字典对象会出现,只要是多层存储的都会出现。比如list中的list,dict,包含多个元素的class对象等。