深拷贝与浅拷贝
深拷贝与浅拷贝
引用赋值
-
基本的原理
graph TB A[list] B[list1] C[数据池-内存] C[数据池-内存]--list变量从内存中取到数据-->A[list] A[list]--通过=直接赋值给list1-->B[list1] B[list1]--list1添加数据内存发生改变-->C[数据池-内存] C[数据池-内存]--list变量的值也随着改变-->A[list] -
引用赋值的变量共用一个内存,一个变量对内存操作,另外的值也会随着改变
list = [1,2,3,4] print(id(list)) 4543631232 list1 = list print(id(list1)) 4543631232 list1.append(6) print(list1) [1, 2, 3, 4, 6] print(list) [1, 2, 3, 4, 6] print(id(list)) 4543631232 # 同一个内存地址
浅层拷贝
-
基本原理
graph TB A[list] B[list数据池-内存] C[list1] D[list1数据池-内存] E[原有对象的深层数据内存] E[原有对象的深层数据内存]--深层数据的内存地址保存在原有对象的内存中-->B[list数据池-内存] B[list数据池-内存]--数据传递给-->A[list] A[list]--拷贝给-->C[list1] C[list1]--创建新的内存存储拷贝的数据-->D[list1数据池-内存] D[list1数据池-内存]--新对象的深层数据地址仍然保存在-->E[原有对象的深层数据内存] -
浅拷贝后创建了新对象,但是新对象的内容和原对象的内容是完全一样的,浅层拷贝只拷贝原有对象的第一层
'''拷贝操作''' list = ['刘洋', '王伟', '张明'] # 方式一:被拷贝对象.copy() list1 = list.copy() print(list1) print(list==list1) print(id(list)) print(id(list1)) print(id(list)==id(list1)) # 方式二:被拷贝对象[:] # 得到的结果和方式一得到的结果是一致的, 这个不是赋值操作,需要注意:切片产生的是新的对象 # 结果是: ['刘洋', '王伟', '张明'] True 4555620832 4555623392 False # 浅层拷贝出来的对象和原对象的内存地址不同,数据内容完全一样,不是一个对象 '''对拷贝后形成的新的对象数据进行操作''' list1.insert(1, '谢大脚') print(list1) print(list) # 结果是: ['刘洋', '谢大脚', '王伟', '张明'] ['刘洋', '王伟', '张明'] # 新对象的操作不会对原对象内存数据产生影响 ----------------- '''浅层拷贝的复杂样式''' ls = [ '葫芦娃', '孙悟空', '功夫熊猫', { '姓名': '小熊猫', '年龄': 1234 } ] ls1 = ls.copy() # 拷贝并赋值给新的对象 ls1[3]['name'] = "乌龟大师" print(ls1) print(ls) # 新对象的改变也造成了原有对象的改变 ls1[0] = "灵鹤" print(ls1) print(ls) # 结果是: ['葫芦娃', '孙悟空', '功夫熊猫', {'姓名': '小熊猫', '年龄': 1234, 'name': '乌龟大师'}] ['葫芦娃', '孙悟空', '功夫熊猫', {'姓名': '小熊猫', '年龄': 1234, 'name': '乌龟大师'}] ['灵鹤', '孙悟空', '功夫熊猫', {'姓名': '小熊猫', '年龄': 1234, 'name': '乌龟大师'}] ['葫芦娃', '孙悟空', '功夫熊猫', {'姓名': '小熊猫', '年龄': 1234, 'name': '乌龟大师'}] ''' 上边的例子中可以看出普通的元素的改变,并不会造成原有对象中数据发生改变, 但是当新对象中的字典对象中的元素发生变化的时候,原有的对象的数据也随着发生了变化,这是因为字典对象虽然在原有的对象中,但是原有的对象只是保存了字典对象的内存地址,实际的数据保存在原有对象对应内存的外部,所以新对象拷贝后得到的也只是字典对象的内存地址,那么,当新对象中改变了字典对象的内存数据后,这些内存数据则会同样影响原有的对象。列表对象同样适应。 '''
深层拷贝
-
基本原理
graph TB A[list] B[list数据池-内存] C[list1] D[list1数据池-内存] E[原有对象的深层数据内存] E[原有对象的深层数据内存]--深层数据的内存地址保存在原有对象的内存中-->B[list数据池-内存] B[list数据池-内存]--数据传递给-->A[list] A[list]--拷贝给-->C[list1] C[list1]--创建新的内存存储拷贝的数据-->D[list1数据池-内存] D[list1数据池-内存]--原有的深层数据创建新的内存地址-->F[深层数据内存] -
深层拷贝是完完全全的拷贝所有的内容
'''深层拷贝''' import copy ls1 = [ '乌龟大师', '孙悟空', '功夫熊猫', { '姓名': '小熊猫', '年龄': 1234, 'name': '乌龟大师' } ] ls2 = copy.deepcopy(ls1) ls2[3]['name'] = "小熊猫师傅" print(ls1) print(ls2) # 结果是 ['灵鹤', '孙悟空', '功夫熊猫', {'姓名': '小熊猫', '年龄': 1234, 'name': '乌龟大师'}] ['灵鹤', '悍娇虎', '功夫熊猫', {'姓名': '小熊猫', '年龄': 1234, 'name': '小熊猫师傅'}] ''' 可以看出:深层拷贝后的对象,可以拷贝多层,每一层元素的改变都不会对原有对象产生影响,深层拷贝需要导入的是copy模块,运用模块中的deepcopy()方法来实现 '''
Note
- 拷贝的原因:
- 用拷贝比正常的创建对象效率高,速度会快很多
- 三者的区别:
- 赋值:内存地址完全一样,一个改变另外一个也随着改变
- 浅层拷贝:只拷贝第一层,如果新对象改变第一层,则原对象不会改变,若改变深层,则原对象随着改变
- 深层拷贝:所有内容全部拷贝,每一层的改变都不会对原有对象数据产生影响