• 【Python】直接赋值,深拷贝和浅拷贝


    直接赋值: 对象的引用,也就是给对象起别名

    浅拷贝: 拷贝父对象,但是不会拷贝对象的内部的子对象。

    深拷贝: 拷贝父对象. 以及其内部的子对象

    在之前的文章中,提到可变对象和不可变对象,接下来也是以这两者的区别进行展开

    很多人学习python,不知道从何学起。
    很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
    很多已经做案例的人,却不知道如何去学习更加高深的知识。
    那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
    QQ群:1097524789

    直接赋值

    对于可变对象和不可变对象,将一个变量直接赋值给另外一个变量,两者 id 值一致,其实本质上是将变量量绑定到对象的过程.

    >>> a=1
    >>> b=a
    >>> id(a) == id(b)
    True
    >>> c="string"
    >>> d=c
    >>> id(c) == id(d)
    True
    >>> e=[1,2,3]
    >>> f=e
    >>> id(e)==id(f)
    True

    关于修改新变量的值,对原有变量会产生的影响,在 可变对象和不可变对象 中也做了讲述,这里通过几个例子,重新温习一下

    不可变对象

    >>> x=1
    >>> y=x
    >>> id(x)==id(y)
    True
    >>> id(1)==id(y)
    True
    >>>>>> id(x)
    1500143776
    >>> y=y+1
    >>> y
    2
    >>> x
    1
    >>> id(x)==id(y)
    False
    >>> id(y)
    1500143808
    >>> id(x)
    1500143776

    对于不可变对象,修改赋值后的新变量,不会对原有变量造成任何影响.为什么出现这种现象呢?因为不可变对象一旦创建之后就不允许被改变.后面对 y 进行的操作,其实是重新创建一个对象并绑定的结果:

    可变对象

    >>> m=[1,2,3]
    >>> n=m
    >>> id(n)==id(m)
    True
    >>> id(m)
    1772066764488
    >>> id(n[0])
    1772066764656
    >>> n[0]=4
    >>> n
    [4, 2, 3]
    >>> m
    [4, 2, 3]
    >>> id(n)==id(m)
    True
    >>> id(m)
    1772066764488

    对于可变对象,修改赋值后的变量,会对原有的变量造成影响,会导致其 value 值的改变,但是其 id 值保持不变

    从上图不难看出,这个时候的 id(n[0]) 的值,和未修改前的 id 值应该不一样,可以输出看一下

    >>>id(n[0])
    1772066764752 # 最初没有修改前是  1772066764656

    n[0] 修改前后为什么 id 值出现改变呢? 首先需要明确一点 n[0] 绑定的是一个不可变对象,在文章的最初提到, 不可变对象一旦创建就不允许修改 .显然对 n[0] 进行修改,不能在绑定对象的内存上进行修改,那如何实现重新赋值呢?只能创建一个新的对象 4 ,然后将 n[0] 绑定到新的对象

    浅拷贝和深拷贝

    先看一下官方文档的定义

    The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or

    class instances).

    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.

    从文档中不难看出,上面提到深拷贝和浅拷贝两者区别在于在复合对象,那接下来也只讨论复合对象.

    浅拷贝

    注意到官方文档也提到对浅拷贝和深拷贝的定义,从上文中不难看出, 浅拷贝构建一个复合对象,然后将原有复合对象包含的对象插入到新的复合对象中

    从上图不难看出, 浅拷贝后,新复合对象包含的对象(可变或者不可变)的 id 值和原有对象包含的对象的 id 值相同

    看一下具体例子:

    >>> import copy
    >>> a=[1,2,[3,4]]
    >>> b=copy.copy(a)
    >>> id(b[0])==id(a[0])
    True
    >>> id(b[2])==id(a[2])
    True
    >>> id(b[2][0])==id(a[2][0])
    True

    现在让我们试着修改一下浅拷贝后的 b 的值,在修改前,可以先思考一下,如果修改 b[0] 可能会发生什么?

    由于 b[0] = 1 ,很显然 1 属于不可变对象,那么根据对不可变变量修改的规则,则 b[0] 会绑定到新的变量上,而 a[0] 的由于没有修改,则保持不变,真的是这样吗?让我们验证一下

    >>> b[0]=5
    >>> b
    [5, 2, [3, 4]]
    >>> a
    [1, 2, [3, 4]]

    接下来我们要尝试修改一下 b[2] ,由于 b[2] 绑定的对象是 list ,属于可变对象,按照上面说的可变对象修改的规则,则修改后的 b[2] 的 id 值保持不变,但是其 value 值会发生改变. 同样的让我们通过例子验证一下

    >>> id(b[2])
    4300618568
    >>> b[2][0]=6
    >>> id(b[2])
    4300618568
    >>> b
    [5, 2, [6, 4]]
    >>> a
    [1, 2, [6, 4]]

    由于 b[2] 和 a[2] 绑定同一个可变对象,很显然对 b[2] 的修改同样会映射到 a[2] 上

    深拷贝

    深拷贝构建一个复合对象,然后递归的将原有复合包含的对象的副本插入到新的复合对象中

    若上图所示, 深拷贝后,新的复合对象包含的对象,若对象为不可变对象,则 id 值保持不变,若对象为可变对象,则 id 值发生改变

    看一个例子:

    >>> import copy
    >>> a=[1,2,[3,4]]
    >>> b=copy.deepcopy(a)
    >>> id(b[0])==id(a[0])
    True
    >>> id(b[2])==id(a[0])
    False
    >>> id(b[2][0])==id(a[2][0])
    True

    接下来让我们修改一下变量 b ,这里就不在修改不可变对象 b[0] 和 b[1] 了,因为结果很明显,对 a 不会产生任何影响,我们来修改 b[2] ,那么修改 b[2] 会对 a[2] 产生影响吗?很明显答案是不会,因为深拷贝就相当于克隆出了一个全新的个体,两者不再有任何关系

    >>> b[2][0]=5
    >>> b
    [1, 2, [5, 4]]
    >>> a
    [1, 2, [3, 4]]
  • 相关阅读:
    jQuery对象和DOM对象
    虚拟主机的部署(Apache)
    事件流:事件冒泡和事件捕获
    ThinkPHP
    级联下拉列表
    今日份抽自己!!!
    c++中关于输入字符数组的一些问题
    今日新知(关于递归中变量的声明)
    格子游戏(并查集)
    1.3-14大象喝水
  • 原文地址:https://www.cnblogs.com/shann001/p/13273188.html
Copyright © 2020-2023  润新知