zoukankan      html  css  js  c++  java
  • python深浅copy探究

    引入

      在python程序中,如果我们操作一个变量的值去做运算,而又想在下次调用时,仍使用原来的变量的值去做运算,那么我们我们就需要将这个变量去做备份,这就是本文所要探究的问题。

    开始

    变量-对象-引用:
      python中全部皆对象,Python中变量是指对象(甚至连type其本身都是对象,type对象)的引用,Python是动态类型,程序运行时候,会根据对象的类型来确认变量到底是什么类型。

    我们有时候会见到这样一种情况:

      a = 1

      b = a

    这样做不就是把数据copy了一份吗,错,这样做只是在程序中新创建了一个对象b,去引对象a创建是指定的值,也就是说,它们是指向了同一块内存地址,而不是在创建 b = a 时又重新在内存中开辟出一块空间来,所以当一个变量的值被修改,则另一个变量的值也会随之被修改,这样说可能不太理解,来个图示吧:

    这个叫做"共享引用",而不是做一个副本(不要犯这样的错哦)。

    正题

    现在就开始探究一下深浅copy

    深浅copy的方法由python内置的一标准库提供(提供的copy方法,适合所有类型对象)
    简单点说

    • copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。
    • copy.deepcopy 深拷贝 拷贝对象及其子对象

    用一个简单的例子来说明一下

    >>> import copy
    >>> a = [1,2,3,['a','b','c']]
    >>> b = a
    >>> c = copy.copy(a)
    >>> d = copy.deepcopy(a)

    a是一个列表,表中的a[3]也是一个列表(也就是一个内部的子对象),b是对a列表的又一个引用,所有a,b是完全相同的,我们可以通过id(a)来验证。

    >>> id(a)
    60356208
    >>> id(b)
    60356208
    >>> id(c)
    63132896
    >>> id(d)
    63133256

    a 和 b的相同也证实了前面所说的共享引用;

    深浅copy的区别:

    浅copy

    >>> import copy
    >>> a = [1,2,3,['a','b','c']]    #a具有两级对象的列表
    >>> b = copy.copy(a)            #创建变量b,使其浅copy a的值
    >>> b
    [1, 2, 3, ['a', 'b', 'c']]
    >>> a[1] = "two"                #当a的父对象修改之后而b的父对象不会被修改
    >>> a
    [1, 'two', 3, ['a', 'b', 'c']]
    >>> b
    [1, 2, 3, ['a', 'b', 'c']]
    >>> a[3][0] = 'A'                #当a的子对象被修改之后b的子对象也会随之修改
    >>> a
    [1, 'two', 3, ['A', 'b', 'c']]
    >>> b
    [1, 2, 3, ['A', 'b', 'c']]

    深copy

    >>> import copy
    >>> a = [1,2,3,['a','b','c']]    #a具有两级对象的列表
    >>> b = copy.deepcopy(a)            #创建变量b,使其深copy a的值
    >>> b
    [1, 2, 3, ['a', 'b', 'c']]
    >>> a[1] = "two"                #当a的父对象修改之后而b的父对象不会被修改
    >>> a
    [1, 'two', 3, ['a', 'b', 'c']]
    >>> b
    [1, 2, 3, ['a', 'b', 'c']]
    >>> a[3][0] = 'A'                #当a的子对象被修改之后b的子对象仍不会随之修改
    >>> a
    [1, 'two', 3, ['A', 'b', 'c']]
    >>> b
    [1, 2, 3, ['a', 'b', 'c']]

     浅拷贝是指拷贝的只是原对象元素的引用,换句话说,浅拷贝产生的对象本身是新的,但是它的内容不是新的,只是对原对象的一个引用

    >>> aList=[[1, 2], 3, 4]
    >>> bList = aList[:] #利用切片完成一次浅拷贝
    >>> id(aList)
    3084416588L
    >>> id(bList)
    3084418156L
    >>> aList[0][0] = 5
    >>> aList
    [[5, 2], 3, 4]
    >>> bList
    [[5, 2], 3, 4]

     但是有点需要特别提醒的,如果对象本身是不可变的,那么浅拷贝时也会产生两个值

    >>> aList = [1, 2]
    >>> bList = aList[:]
    >>> bList
    [1, 2]
    >>> aList
    [1, 2]
    >>> aList[1]=111
    >>> aList
    [1, 111]
    >>> bList
    [1, 2]

    为什么bList的第二个元素没有变成111呢?因为数字在python中是不可变类型!!

     在这顺便回顾下Python标准类型的分类:

    • 可变类型: 列表,字典
    • 不可变类型:数字,字符串,元组

    理解了浅拷贝,深拷贝是什么自然就很清楚了。
    python中有一个模块copy,deepcopy函数用于深拷贝,copy函数用于浅拷贝。
    最后,对象的赋值是深拷贝还是浅拷贝?
    对象赋值实际上是简单的对象引用

    >>> a = 1
    >>> id(a)
    135720760
    >>> b = a
    >>> id(b)
    135720760

     a和b完全是一回事。

  • 相关阅读:
    vscode 的tab空格设置设置为4的方法
    【vue生命周期】- 详解
    javascript中call()、apply()、bind()的用法终于理解
    彻底理解js中this的指向,不必硬背。
    OKR群:为什么说每个程序员都应该有自己的个人OKR
    2019年程序员最值得学习的思维利器——任务分解
    代码之美——《重构》、《代码整洁之道》
    为什么说程序员都应该写一写博客
    我的第一篇博客
    为什么说程序员都应该玩一玩GitHub
  • 原文地址:https://www.cnblogs.com/zhichaoma/p/7493154.html
Copyright © 2011-2022 走看看