zoukankan      html  css  js  c++  java
  • copy深浅拷贝

      我们在很多方法里都看到copy()方法,这是对变量的复制,赋值,下面来看一下实例:

        复制方法调用的是copy模块中的方法:

        import copy

      copy.copy()         #前拷贝

      copy.deepcopy()     #深拷贝

        我们可以让一个变量等于另一个变量可以采用赋值的方式,比如a = b等,让变量a = b变量,还可以通过copy()来实现。下面来看看在各种情况下的关联情况:

        一、字符串和数字的情况

        >>> import copy
      >>> a = 3
      >>> b = a
      >>> c = copy.copy(a)
      >>> d = copy.deepcopy(a)
      >>> b
      3
      >>> c
      3
      >>> d
      3
        >>> print(id(a),id(b),id(c),id(d))
      10914432 10914432 10914432 10914432
        从上面可以看出,我们通过导入模块copy,这个模块专门用于复制,可以看到在数字中,采用赋值、copy()、deepcopy()三种方式,我们发现采用三种方式的方式,都是把地址关联过去,具有相同的地址,说明是采用如下方式进行管理的。实例如下:

       

        从上图可以看出,在数字和字符串中,三种任意方式都是关联到字符串或数字所在的内存,是把内容关联过去,因此无论采用那种方式都是一样的

    。下面来看一看在列表,元组、字符串、字典中的情况。

    二、列表,元组,字典一层复制情况

        列表、字典的情况

        1、在列表中的情况

        import copy
      l = ["alex",11,"sb","tom"]
      d = {"k1":"v1","k2":22,"k3":"alex"}
      t = (11,'ALEX',"sb")

      l1 = l
      l2 = copy.copy(l)
      l3 = copy.deepcopy(l)

      print(id(l),id(l1),id(l2),id(l3))

      #下面来修改一下列表中的元素,看看关联情况编程什么样了,如下:
      l.append("Aoi")
      print(l,l1,l2,l3)
      print(id(l),id(l1),id(l2),id(l3))
        2、在字典中的情况
      d1 = d
      d2 = copy.copy(d)
      d3 = copy.deepcopy(d)
      print(id(d),id(d1),id(d2),id(d3))
      d.__setitem__("tom","Hello")
      print(d," ",d1," ",d2," ",d3)
      print(id(d),id(d1),id(d2),id(d3))

      运行结果如下:

        列表中的运算结果:

        140006457636360 140006457636360 140006457672456 140006457637320
      ['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom'] ['alex', 11, 'sb', 'tom']
      140006457636360 140006457636360 140006457672456 140006457637320
      140006482186568 140006482186568 140006457674440 140006457636680
      字典中的运算结果:

        {'k2': 22, 'k3': 'alex', 'tom': 'Hello', 'k1': 'v1'}
      {'k2': 22, 'k3': 'alex', 'tom': 'Hello', 'k1': 'v1'}
       {'k2': 22, 'k1': 'v1', 'k3': 'alex'}
      {'k2': 22, 'k1': 'v1', 'k3': 'alex'}
      140006482186568 140006482186568 140006457674440 140006457636680

        可以看出,在列表中我们通过等号赋值(=)、copy(list)、deepcopy(list)方法打印变量的ip地址,可以看出,等号赋值(=)与原来变量的地址是一样的,因此等号的赋值方式是这样的:

       

        等号赋值无论在关联字典还是列表的过程中,都是指向同一个Python开辟的内存地址,a和b的内存地址永远是一致的,只要a发生了变化,相应的b就发生变化。

        而在字典中copy()和deepcopy()确是下面的形式:

       

        为什么我猜测copy()是上面的形式呢,我们来看一段代码:

        import copy
      l = ["alex",11,"sb","tom"]
      d = {"k1":"v1","k2":22,"k3":"alex"}                                   (1)
      t = (11,'ALEX',"sb")

      l1 = l
      l2 = copy.copy(l)
      l3 = copy.deepcopy(l)

      print(id(l),id(l1),id(l2),id(l3))

      #下面来修改一下列表中的元素,看看关联情况编程什么样了,如下:
      l.append("Aoi")
      print(l,l1,l2,l3)
      print(id(l),id(l1),id(l2),id(l3))

      d1 = d
      d2 = copy.copy(d)                                        (2)
      d3 = copy.deepcopy(d)
      print(id(d),id(d1),id(d2),id(d3))                        (3)
      d.__setitem__("tom","Hello")
      print(d," ",d1," ",d2," ",d3)
      print(id(d),id(d1),id(d2),id(d3))                         (4)

      del d["k1"]                                               (5)
      print(d," ",d1," ",d2," ",d3)
      print(id(d),id(d1),id(d2),id(d3))                          (6)

        代码运行如下:

        140353118074376 140353118074376 140353118110472 140353118074760
      ['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom'] ['alex', 11, 'sb', 'tom']
      140353118074376 140353118074376 140353118110472 140353118074760
      140353142624584 140353142624584 140353118112456 140353118075272
      {'k1': 'v1', 'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
       {'k1': 'v1', 'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
       {'k1': 'v1', 'k2': 22, 'k3': 'alex'}
       {'k1': 'v1', 'k2': 22, 'k3': 'alex'}
      140353142624584 140353142624584 140353118112456 140353118075272
      {'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
       {'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
       {'k1': 'v1', 'k2': 22, 'k3': 'alex'}
       {'k1': 'v1', 'k2': 22, 'k3': 'alex'}
      140353142624584 140353142624584 140353118112456 140353118075272

        在上面(1)处我们定义了一个字典,在(2)处我们使用copy.copy()产生一个新的变量d2,然后我们打印变量d、d2的id(d)、id(d2),我们可以看出,两者的id()是不一样的,因此可以说明在系统中是存在了两个位置存放d和d2的,而不是一个位置,仅凭这一点还不足以说明,下面来看(5)处,我们删除了字典d中的键-值对"k1",此时如果两者存在关联的话,那么d2中键-值对"k1":"v1"必然也会被删除,事实上并没有,而且我们修改元素的时候,如果它们之间存在指向关系的话,那么copy()也会让d2中的添加一个键-值对"tom":"Hell0"。事实上并没有,所以我断定,无论怎样使用copy()方法都是在内存中新开辟了一个地址,如果只有一层的话,这两个地址之间也是没有关联的。

        如果字典只有一层,那么使用deepcopy()方法也是一样的,图例如下:

       

    三、列表,元组,字典多层情况的赋值情况

       上面我们研究了copy()、deepcopy()单层的情况,下面来看看多层的情况,首先定义一个字典n1={"k1":123,"k2":"wupie","k3":[123,"alex"]}

    ,

         在python中,copy()、deepcopy()的设置挺复杂的,相同元素的id是一样的,但是在删除的时候又不会影响由copy()、deepcopy()产生的变量,

    但是在使用copy()的时候,第二层的元素还是与原来的元素关联在一起,下面来看一个例子:

        import copy

      n1 = {"k1":123,"k2":"wupie","k3":[456,"alex"]}

      #打印k1ip地址
      n2 = copy.copy(n1)
      n3 = copy.deepcopy(n1)

      print(n1," " ,n2," ",n3)
      print(id(n1),id(n2),id(n3))
      print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"])," ")

      #打印k2的地址
      print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"])," ")

      #打印"k3"ip地址
      print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"])," ")

      #修改“k1"的值
      n1["k1"] = 888

      #打印修改后的信息
      print(n1," " ,n2," ",n3)
      print(id(n1),id(n2),id(n3))
      print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"])," ")

      #打印修改后的k2的地址
      print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"])," ")

      #打印"k3"ip地址
      print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"])," ")

      #修改"k3"中的值
      n1["k3"][0] = 666
      print(n1," " ,n2," ",n3)
      print(id(n1),id(n2),id(n3))
      print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"])," ")

      #打印修改后的k2的地址
      print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"])," ")

      #打印"k3"ip地址
      print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"])," ")

      #删除"k3"的键值对
      del n1["k3"]
      print(n1," " ,n2," ",n3)
      print(id(n1),id(n2),id(n3))print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"])," ")

      #打印修改后的k2的地址

      print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"])," ")

      try:#打印"k3"的ip地址

        print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"])," ")

      except KeyError:

         print(id(n2["k3"]),id(n3["k3"]))id(n2),id(n3))print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"])," ")#打印修改后的k2的地址print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"])," ")try:#打印"k3"的ip地址 print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"])," ")except KeyError: print(id(n2["k3"]),id(n3["k3"]))

        运行结果如下:

        {'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
       {'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
      {'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
      139928164286856 139928139772744 139928139736968
      10918272 10918272 10918272

      139928163731640 139928163731640 139928163731640

      139928139736520 139928139736520 139928139737608           (k3)的ip地址

      {'k3': [456, 'alex'], 'k1': 888, 'k2': 'wupie'}
       {'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
       {'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
      139928164286856 139928139772744 139928139736968
      139928164089648 10918272 10918272

      139928163731640 139928163731640 139928163731640

      139928139736520 139928139736520 139928139737608

      {'k3': [666, 'alex'], 'k1': 888, 'k2': 'wupie'}
       {'k3': [666, 'alex'], 'k1': 123, 'k2': 'wupie'}
       {'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
      139928164286856 139928139772744 139928139736968
      139928164089648 10918272 10918272

      139928163731640 139928163731640 139928163731640

      139928139736520 139928139736520 139928139737608

      {'k1': 888, 'k2': 'wupie'}
       {'k3': [666, 'alex'], 'k1': 123, 'k2': 'wupie'}
       {'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
      139928164286856 139928139772744 139928139736968
      139928164089648 10918272 10918272

      139928163731640 139928163731640 139928163731640

      139928139736520 139928139737608

        在上面例子中,我们首先定义了一个变量n1,里面嵌套了一层字典,然后使用copy(),deepcopy()生成了新的变量n2,n3并且打印了n1,n2,n3的ip地址,由ip地址可以看出,n1,n2,n3是在内存中有不同的存储位置的,接着我们打印了键-值对“k1”的存储id,结果发现,三者的“k1”存储的id位置是一样的,说明还是用的原来位置的id,这样节省了内存,接着我们看“k3”的ip地址,可以看出,使用copy()得到的ip地址与n1的“k3”的id是一样的,说明是用的一个id,我们修改字典n1中的元素"k3"之后,n2也跟着变化,说明字典n1中的“k3”和字典n2中的“k3”存在某种管理,但是当我们删除字典n1中的“k3”之后,字典n2中的"k3"不受影响,还存在,说明使用copy()生成的变量,第二层关联之间存在着某种关联,但是又不完全依存,第一层之间共用一个地址,节省了内存,但是在原来的字典发生变化的时候又不影响之前的变量,只是对新的变量开辟了一个空间,用来存放位置。

       

        有一个监控模板,包含内存,硬盘,有一批机器,现在是按dic模式运行的,现在要修改其中一部分的及其的硬盘,其他部分不改变。

        import copy
      dic = {
      "cpu":[80,],
      "men":[80,],
      "disk":[80]
      }

      print("before:",dic)
      new_dic = copy.deepcopy(dic)
      new_dic["cpu"][0] = 50

      print(dic," ",new_dic)

        在上面,我们使用copy模块的deepcopy来进行处理,我们知道,有很多信息,在嵌套中,只有deepcopy()才会生成第二层的信息。

  • 相关阅读:
    226. 翻转二叉树
    LeetCode 1660.纠正二叉树(Medium)
    814. 二叉树剪枝
    110. 平衡二叉树
    HTTPS原理浅析
    MySQL知识网络
    制作SSL证书(签发免费证书)
    Redis高可用三(Redis Cluster集群)
    Redis高可用二( 哨兵sentinel)
    Redis高可用一(主从)
  • 原文地址:https://www.cnblogs.com/gengcx/p/6772324.html
Copyright © 2011-2022 走看看