• Python中的浅拷贝以及深拷贝


    Python中数据类型
    不可变数据对象
    不可变指的是数据存储到内存后无法进行修改。
    python中的不可变数据类型有:int、float、str、tuple、bool

    可变数据类型
    可变指的是数据存储后可以进行修改。
    python中的可变数据类型有:list、dict、set

    代码表示

    >>>print('修改前:')
    >>>i = 1
    >>>f = 5.2
    >>>s = 'hello'
    >>>t = (1,2,3)
    >>>b = True
    >>>print('i={},id(i)={}
    f={},id(f)={}
    s={}id(s)={}
    t={},id(t)={}
    b={},id(b)={}
    '.format(i,id(i),f,id(f),s,id(s),t,id(t),b,id(b)))
    >>>print('修改后:')
    >>>i = 2
    >>>f = 5.3
    >>>s = 'helloWorld'
    >>>t = (4,5,6)
    >>>b = False
    >>>print('i={},id(i)={}
    f={},id(f)={}
    s={}id(s)={}
    t={},id(t)={}
    b={},id(b)={}
    '.format(i,id(i),f,id(f),s,id(s),t,id(t),b,id(b)))

    输出结果
    修改前:
    i=1,id(i)=1596320880
    f=5.2,id(f)=2558329694656
    s=helloid(s)=2558344746464
    t=(1, 2, 3),id(t)=2558344774928
    b=True,id(b)=1596063952
    修改后:
    i=2,id(i)=1596320912
    f=5.3,id(f)=2558329694920
    s=helloWorldid(s)=2558340497008
    t=(4, 5, 6),id(t)=2558344775000
    b=False,id(b)=1596063984

    结论
    对python中不可变数据类型进行重复赋值(修改),实际上是重新将变量名指向了新的内存地址。
    而对于python中可变数据类型,读者自己动手尝试后也会发现,修改前后变量名所指向的地址是不变的,这里不再赘述。
    ps:对于除tuple外的int、float、str、bool四种数据类型,相同的值在python中内存的位置是相同的。

    浅拷贝与深拷贝
    先明确一点,这里讨论的都是基于可变数据对象的,原因见上文。
    根据官方文档对于copy.copy()以及copy.deepcopy()两个方法的描述:

    深浅拷贝间的差异仅仅反应在对于复合对象的拷贝中,即包含其他对象的对象。
    其次,官方对于深浅拷贝也有着描述:

    浅拷贝构造了一个新的复合对象,然后将从从原始对象中找到的引用插入到新对象中。
    深拷贝则是将原始对象的副本插入到了新对象中。
    简单来说,对于复合对象而言:
    浅拷贝后,改变原始对象中可变类型的数据的值,会同时影响拷贝对象
    深拷贝后,改变原始对象中可变类型的数据的值,不会同时影响拷贝对象。

    代码表示

    >>>import copy
    >>>print('修改前:')
    >>> list1 = [[1,2,3],'wx',3]
    >>> list2 = list1  # 直接将原列表的引用赋值给list2
    >>> list3 = list1[:]  # 切片后赋值给list3,效果与浅拷贝一样
    >>> list4 = copy.copy(list1)  # 浅拷贝
    >>> list5 = copy.deepcopy(list1)  # 深拷贝
    >>>print('list1={},id(list1)={},id(list1[0])={}
    list2={},id(list2)={},id(list2[0])={}
    list3={},id(list3)={},id(list3[0])={}
    list4={},id(list4)={},id(list4[0])={}
    list5={},id(list5)={},id(list5[0])={}
    '.format(list1,id(list1),id(list1[0]),list2,id(list2),id(list2[0]),list3,id(list3),id(list3[0]),list4,id(list4),id(list4[0]),list5,id(list5),id(list5[0])))
    >>>print('修改后:')
    >>>list1.append(6)
    >>> list1[0].append(4)
    >>> print('list1={},id(list1)={},id(list1[0])={}
    list2={},id(list2)={},id(list2[0])={}
    list3={},id(list3)={},id(list3[0])={}
    list4={},id(list4)={},id(list4[0])={}
    list5={},id(list5)={},id(list5[0])={}
    '.format(list1,id(list1),id(list1[0]),list2,id(list2),id(list2[0]),list3,id(list3),id(list3[0]),list4,id(list4),id(list4[0]),list5,id(list5),id(list5[0])))

    输出结果
    修改前:
    list1=[[1, 2, 3], ‘wx’, 3],id(list1)=1778195532040,id(list1[0])=1778195665224
    list2=[[1, 2, 3], ‘wx’, 3],id(list2)=1778195532040,id(list2[0])=1778195665224
    list3=[[1, 2, 3], ‘wx’, 3],id(list3)=1778195665032,id(list3[0])=1778195665224
    list4=[[1, 2, 3], ‘wx’, 3],id(list4)=1778195586696,id(list4[0])=1778195665224
    list5=[[1, 2, 3], ‘wx’, 3],id(list5)=1778195586760,id(list5[0])=1778195586888
    修改后:
    list1=[[1, 2, 3, 4], ‘wx’, 3, 6],id(list1)=1778195532040,id(list1[0])=1778195665224
    list2=[[1, 2, 3, 4], ‘wx’, 3, 6],id(list2)=1778195532040,id(list2[0])=1778195665224
    list3=[[1, 2, 3, 4], ‘wx’, 3],id(list3)=1778195665032,id(list3[0])=1778195665224
    list4=[[1, 2, 3, 4], ‘wx’, 3],id(list4)=1778195586696,id(list4[0])=1778195665224
    list5=[[1, 2, 3], ‘wx’, 3],id(list5)=1778195586760,id(list5[0])=1778195586888

    结论
    OK,代码很好懂,但是输出结果较多,我们先看修改前输出的数据,根据地址来进行判断。
    list2相当于list1的引用,所以无论是浅层数据结构(不可变数据)还是深层数据结构(可变数据)都与list1相同。
    list3、list4效果一样,均为list1的浅拷贝,两对象的地址均不同于list1,但当涉及到深层数据结构(可变数据list1[0]为列表)时,实际还是指向了原列表list1.
    list5为list1的深拷贝,可以看出无论其本身对象还是其中的深层数据结构(可变数据list1[0]为列表)都为副本。
    接着是修改后输出的数据。
    list1、list2不再赘述,两者不管谁改变,都会互相影响。
    深浅拷贝后,均生成了新的对象,所以原对象中的浅层次数据结构(不可变数据)的增加减少不会影响list3、list4,但是对于深层次数据结构(可变数据list1[0]为列表)来说,新列表list3、list4中的相应元素还是指向原列表list1,所以当原列表list1中的list1[0](深层次数据结构)发生改变时,浅拷贝出的list3、list4也会受到影响(反之亦然)。
    对于深拷贝生成的list5,无论时深层次还是浅层次都为原对象的副本,所以两者不会互相影响。
    简而言之,浅拷贝更像是“藕断丝连”式的拷贝,而深拷贝则是完完全全的“复制粘贴”。
     


    ————————————————
    版权声明:本文为CSDN博主「我在北海北」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/l425357138/article/details/105671243

  • 相关阅读:
    设计模式之外观模式(结构型)
    Oracle merge合并更新函数
    前端自定义搜索框实现
    Easyui学习整理笔记
    Jquery+Eayui实现列表选择功能
    Oracle SQL优化器简介
    设计模式之原型模式(创建型)
    Mysql学习笔记整理手册
    Oracle和Mysql语法异同整理笔记
    Mysql实现树形递归查询
  • 原文地址:https://www.cnblogs.com/LQZ888/p/12762382.html
Copyright © 2020-2023  润新知