zoukankan      html  css  js  c++  java
  • 直接赋值,深拷贝与浅拷贝

    首先,简单理解一下概念:(注意:以下概念都是建立在可变数据类型上,包括列表list和字典dict)

    1、直接赋值:当创建一个对象a,然后把它赋给另一个变量b的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用;原始列表改变,被赋值的b也会做相同的改变;

     

     

     

    2、copy浅拷贝,只拷贝了父对象,没有拷贝子对象,所以原始数据的子对象的改变,浅拷贝的子对象也会改变;但是父对象的改变,浅拷贝的父对象不会改变;

     

     

     

    3、深拷贝,包含父对象里面的子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变;

     

     

     接下来我们来跑一个代码例子,原始对象包含子对象的例子

    import copy# 列表型,即可变数据类型,但不包含子对象
    a=[1,2]
    b=copy.deepcopy(a)
    c=a
    d=copy.copy(a)
    e=[1,2]
    print(b is a)
    print(c is a)
    print(d is a)
    print(e is a)
    print("变化前:",a,b,c,d,e,"
    ")
    a.append(5)
    print("变化后:",a,b,c,d,e,"
    ")

    输出结果:

    False
    True
    False
    False
    变化前: [1, 2] [1, 2] [1, 2] [1, 2] [1, 2]
    变化后: [1, 2, 5] [1, 2] [1, 2, 5] [1, 2] [1, 2]

    分析:

    1、我们创建一个列表型数据a,即可变数据类型,但不包含子对象;

    PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象

    x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

    2、b深拷贝a,与a不是引用自一个对象,所以输出false

    3、c是a直接赋值的,拷贝了a的引用,即与a引用自同一个对象,所以输出true

    4、d浅拷贝a,与a也不是引用自同一个对象,所以输出false

    5、e虽然和a值一样,但属于不同的对象,在内存中有不一样的地址,所以输出false

    6、a对象增加值5,只有直接赋值的c的值同步发生了改变,因为深拷贝和浅拷贝的父对象和原始对象都是不一样的了(可以回头看看概念和图例),而e对象本来就是与a无关的,所以更加不会发生变化。

    我们再跑一个代码例子,原始对象包含子对象的例子

    import copy
    #
    列表型,即不可变数据类型,但包含子对象 a=[1,2,[11,22]] b=copy.deepcopy(a) c=a d=copy.copy(a) e=[1,2,[11,22]] print(b is a) print(c is a) print(d is a) print(e is a) print("变化前:",a,b,c,d,e," ") a[2].append(33) print("变化后:",a,b,c,d,e," ")

    输出结果:

    False
    True
    False
    False
    变化前: [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]]
    
    变化后: [1, 2, [11, 22, 33]] [1, 2, [11, 22]] [1, 2, [11, 22, 33]] [1, 2, [11, 22, 33]] [1, 2, [11, 22]]

    分析:

    1、我们创建一个列表型数据a,即可变数据类型,且包含子对象,子对象也是个列表;

    PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象

    x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

    2、b深拷贝a,与a不是引用自一个对象,所以输出false

    3、c是a直接赋值的,拷贝了a的引用,即与a引用自同一个对象,所以输出true

    4、d浅拷贝a,与a也不是引用自同一个对象,所以输出false

    5、e虽然和a值一样,但属于不同的对象,在内存中有不一样的地址,所以输出false

    6、a对象的子对象列表增加值33,除了直接赋值的c的值同步发生了改变,浅拷贝的子对象也发生了改变,因为浅拷贝的子对象和原始对象中的子对象引用的是同一个对象!(可以回头看看概念和图例),而e对象本来就是与a无关的,所以依然不会发生变化。

     

    最后,我们来思考一个问题,如果是不可变数据类型,结果是什么?

    import copy
    # 数值型,即不可变数据类型
    a=1
    b=copy.deepcopy(a)
    c=a
    d=copy.copy(a)
    e=1
    print(b is a)
    print(c is a)
    print(d is a)
    print(e is a)
    print("变化前:",a,b,c,d,e,"
    ")
    a=2
    print("变化后:",a,b,c,d,e,"
    ")

    输出结果:

    True
    True
    True
    True
    变化前: 1 1 1 1 1
    
    变化后: 2 1 1 1 1

    分析:

    1、我们创建一个数值型数据a,即不可变数据类型;

    PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象

    x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

    2、结果发现无论是深拷贝、浅拷贝、直接赋值还是新建一个数值一样的变量,在内存中的地址都是一样的,身份运算输出都是true。这是因为:不可变数据类型,不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象(一个地址)!

    6、所以当a变量的值改变之后,其他的变量都不会改变,因为是a引用的对象变了,而其他变量的引用并没有发生改变,依然引用“数值1”这个对象。

    由此可见,对于不可变数据类型(数值型、字符串型和元组),拷贝都是无差别的。

  • 相关阅读:
    一文让你明白Redis持久化
    spring-data-redis 2.0 的使用
    中间自适应布局的5种解法
    php实现只需要一个QQ号就可以获得用户信息
    基于LINUX下的进程管理问题
    【初码干货】记一次分布式B站爬虫任务系统的完整设计和实施
    初码-爬虫系列-文章目录
    初码-阿里云系列-文章目录
    初码-Azure系列-存储队列的使用与一个Azure小工具(蓝天助手)
    初码-Azure系列-记一次MySQL数据库向Azure的迁移
  • 原文地址:https://www.cnblogs.com/cyanlee/p/12296044.html
Copyright © 2011-2022 走看看