浅拷贝和深拷贝详解

官方文档:

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts the same objects into it that the original contains.
  • A deep copy constructs a new compound object and then, recursively,inserts copies into it of the objects found in the original.

在python中,对象赋值实际上是对象的引用。

  • 浅拷贝: 拷贝对象的值,但不拷贝对象内部元素的值,只拷贝内部元素的引用

    >>> SL = {'name': 'SL',  'friend': ['A', 'B', 'C']}
    >>> YS = SL.copy()
    

    查看SL,YS的id值

    >>> print id(SL), id(YS)
    139783840481360 139783840476248
    

    可以看出,两者的id值是不同的,说明拷贝对象的值。
    接下来查看SL[‘name’],YS[‘name’] 以及 SL[‘friend’],YL[‘friend’]的id值。

    >>> print id(SL['name']), id(YS['name'])
    139783840488224 139783840488224
    >>> print id(SL['friend']), id(YS['friend'])
    139783840438608 139783840438608
    

    内部元素的id值分别对应相同,说明都是指向相同对象。
    下面对SL作出修改,然后查看SL和YS的状态

    >>> SL['name'] = 'SS'
    >>> SL['friend'][0] = 'Z'
    >>> SL
    {'name': 'SS', 'friend': ['Z', 'B', 'C']}
    >>> YS
    {'name': 'SL', 'friend': ['Z', 'B', 'C']}
    

    SL[‘name’]指向字符串(不可变对象),SL[‘friend’]指向是列表(可变对象)。
    可以看出,在替换SL中的不可变对象时,YS不受影响,修改SL中的可变对象时,YS也会相应改变。
    分析:
    SL[‘name’],YS[‘name’]原本指向相同对象,由于SL[‘name’]指向的是不可变对象。所以当改变SL[‘name’]时,会创建一个新的字符串对象,并使SL[‘name’]指向它,YS[‘name’]仍然指向原本对象。
    SL[‘frined’],YS[‘friend’]指向相同对象(即列表),属于可变对象。因而修改SL[‘friend’]时,不需要创建新对象,直接修改SL[‘friend’]指向的列表。

    查看一下改变之后SL[‘name’],YS[‘name’]和SL[‘friend’],YS[‘friend’]的id值

    >>> print id(SL['name']), id(YS['name'])
    139783774899256 139783840488224
    >>> print id(SL['friend']), id(YS['friend'])
    139783840438608 139783840438608
    

    前两者的id值已经不同,后两者的id值相同,由此可见,上述分析是正确的。

因此,浅拷贝会得到一个新的对象,但对于对象内部的元素,无论是可变对象还是不可变对象都只拷贝引用

  • 深拷贝: 拷贝对象的值,拷贝不可变元素的引用,拷贝可变元素的值

    >>> SL = {'name': 'SL',  'friend': ['A', 'B', 'C']}
    >>> YS = deepcopy(SL)

    查看SL,YS的id值

    >>> print id(SL), id(YS)
    139732549292672 139732549294912
    

    两者的id值不同,说明拷贝对象的值。接下来查看SL[‘name’],YS[‘name’] 以及 SL[‘friend’],YL[‘friend’]的id值。

    >>> print id(SL['name']), id(YS['name'])
    139732549298976 139732549298976
    >>> print id(SL['friend']), id(YS['friend'])
    139732549249360 139732549249216
    

    前两者的id值相同,后两者的id值不同。这里也对SL作出修改,然后查看SL和YS的值

    >>> SL['name'] = 'SS'
    >>> SL['friend'][0] = 'Z'
    >>> SL
    {'name': 'SS', 'friend': ['Z', 'B', 'C']}
    >>> YS
    {'name': 'SL', 'friend': ['A', 'B', 'C']}
    

    不管对SL作出怎么的修改都不会影响到YS的值
    分析:
    修改SL[‘name’]时,同上
    SL[‘frined’],YS[‘friend’]原本就指向不同对象,修改SL[‘friend’]时,明显不会影响到YS的值。

    下面查看一下改变之后SL[‘name’],YS[‘name’]和SL[‘friend’],YS[‘friend’]的id值

    >>> print id(SL['name']), id(YS['name'])
    139732549296616 139732549298976
    >>> print id(SL['friend']), id(YS['friend'])
    139732549249360 139732549249216
    

    意料之中,仍然对应不相同

    因此,深拷贝也会得到一个新的对象,对于对象的内部元素,拷贝不可变对象的引用,拷贝可变对象的值

总而言之,浅拷贝得到的副本,修改副本内部的可变对象时会影响到原始对象;深拷贝得到的副本 ,无论如何修改副本都不会影响到原始对象。

注:浅拷贝和深拷贝只有在关于复合对象(包含其它对象的对象,列表,类等)才有区别。对于不可变对象,没有被拷贝的说法,即使用deepcopy,查看id值也是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值