美文网首页python
还没彻底理解python浅复制和深复制的看过来!

还没彻底理解python浅复制和深复制的看过来!

作者: 给力的昵称 | 来源:发表于2020-04-22 19:03 被阅读0次

    浅复制的影响

    浅复制和深复制的区别在于,浅复制只复制引用到新的列表中(引用可以理解为地址),不会创建新对象。而深复制创建新的对象,并把对象保存在新的地址中。浅复制和深复制对可变和不可变序列的影响是不一样的。对可变序列的浅复制会带来意想不到的结果。看示例1

    #示例1
    >>>a = [[1],2,3,4]
    >>>b = list(a)
    >>>a[0].append(0)
    >>>a
    [[1, 0], 2, 3, 4] 
    >>>b
    [[1, 0], 2, 3, 4] 
    

    对于复制列表,最简单的方式是使用内置类型的构造方法list(),也能使用[:]复制副本。不管是构造方法还是[:]都是浅复制。从示例1可以看到,对a的第0个元素进行了修改,但是b也发生了改变。为什么呢?我先要理解a和b之间发生了什么?见下面图1。


    图1

    因为浅复制只是复制了引用到新的列表中,他们的引用还是一样的,a和b的第0个元素都是指向列表[1],因为列表是可变序列,可以原地修改,所以修改后引用不变。这就导致了a的修改会带来了b的改变。再看看示例2

    示例2
    >>>a = [1,2,3,4]
    >>>b = list(a)
    >>>a[0]=0
    >>>a
    [0, 2, 3, 4] 
    >>>b
    [1, 2, 3, 4] 
    

    示例2中a的修改并没有带有b的变化,他们之间有发生了什么?看下面图2。

    图2

    因为浅复制的原因,本来a,b的引用都是一样的,然后对a的第0元素进行了修改,由于该元素是不可变序列,要改变只能重新创建新的对象,所以a的第0个元素的引用发生了改变,但这并不影响到b的第0个元素的引用。好了,再看一个复杂点的例子,看示例3。

    #示例3
    >>>l1=[1,[2,3,4],(5,6,7)]
    >>>l2=list(l1)
    >>>l1.append(10)#1
    >>>l1[1].remove(3)#2
    >>>l2[1] +=[8,9]#3
    >>>l2[2] += (10,11)#4
    

    1.l2修改对l2没影响
    2.l2修改对l2有影响
    3.l2修改对l1有影响
    4.l2修改对l1没影响

    如何深复制

    浅复制的结果可能不是你想要的,那么如何做深复制呢?。事实上,copy模块提供的copy和deepcopy函数能为任意对象做浅复制和深复制,看示例4。

    #示例4
    >>>import copy 
    >>>l1=[1,[2,3,4],(5,6,7)]
    >>>l2=copy.deepcopy(l1)
    >>>l3=copy.copy(l1)
    >>>l1[1].remove(3)
    >>>l1
    [1,[2,4],(5,6,7)]
    >>>l2
    [1,[2,3,4],(5,6,7)]
    >>>l3
    [1,[2,4],(5,6,7)]
    

    l2是l1的深复制,l3是l2的浅复制,对l1第1个元素进行了修改,虽然该元素是可变对象,影响了l3,但是没有影响到l2。因为l2是深复制的原因,所以是创建了新的对象,有了新的引用,可以说是跟l2没有一毛钱关系了,他们只是内容一样而已。最后看一个有趣的现象,看示例5。

    #示例5
    >>>l1=[1,[2,3,4],(5,6,7)]
    >>>l1.append(l1)
    >>>l1
    [1, [2, 4], (5, 6, 7), [...]]
    

    看l2最后的元素居然是神奇的[...],这究竟是什么回事?看看下面图3的引用就知道了,来!


    图3

    可以看到,列表最后元素的引用指向了自身,自身的最有元素还是指向自身,这是一个无限循环引用,所以出现了[...]

    相关文章

      网友评论

        本文标题:还没彻底理解python浅复制和深复制的看过来!

        本文链接:https://www.haomeiwen.com/subject/iubwihtx.html