深拷贝与浅拷贝

深拷贝与浅拷贝

引用赋值

  • 基本的原理

    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

  • 拷贝的原因:
    • 用拷贝比正常的创建对象效率高,速度会快很多
  • 三者的区别:
    • 赋值:内存地址完全一样,一个改变另外一个也随着改变
    • 浅层拷贝:只拷贝第一层,如果新对象改变第一层,则原对象不会改变,若改变深层,则原对象随着改变
    • 深层拷贝:所有内容全部拷贝,每一层的改变都不会对原有对象数据产生影响
posted @ 2020-01-09 20:37  大道至诚  阅读(138)  评论(0编辑  收藏  举报