copy深淺拷貝

  咱們在不少方法裏都看到copy()方法,這是對變量的複製,賦值,下面來看一下實例:python

    複製方法調用的是copy模塊中的方法:編程

    import copyapp

  copy.copy()         #前拷貝spa

  copy.deepcopy()     #深拷貝
3d

    咱們可讓一個變量等於另外一個變量能夠採用賦值的方式,好比a = b等,讓變量a = b變量,還能夠經過copy()來實現。下面來看看在各類狀況下的關聯狀況:blog

    1、字符串和數字的狀況ip

    >>> 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()三種方式,咱們發現採用三種方式的方式,都是把地址關聯過去,具備相同的地址,說明是採用以下方式進行管理的。實例以下:
內存

   

    從上圖能夠看出,在數字和字符串中,三種任意方式都是關聯到字符串或數字所在的內存,是把內容關聯過去,所以不管採用那種方式都是同樣的字符串

。下面來看一看在列表,元組、字符串、字典中的狀況。it

2、列表,元組,字典一層複製狀況

    列表、字典的狀況

    一、在列表中的狀況

    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))
    二、在字典中的狀況
  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,"\n",d1,"\n",d2,"\n",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,"\n",d1,"\n",d2,"\n",d3)
  print(id(d),id(d1),id(d2),id(d3))                         (4)

  del d["k1"]                                               (5)
  print(d,"\n",d1,"\n",d2,"\n",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()方法也是同樣的,圖例以下:

   

 

3、列表,元組,字典多層狀況的賦值狀況

   上面咱們研究了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,"\n" ,n2,"\n",n3)
  print(id(n1),id(n2),id(n3))
  print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")

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

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

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

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

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

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

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

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

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

  #刪除"k3"的鍵值對
  del n1["k3"]
  print(n1,"\n" ,n2,"\n",n3)
  print(id(n1),id(n2),id(n3))print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")

  #打印修改後的k2的地址

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

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

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

  except KeyError:

     print(id(n2["k3"]),id(n3["k3"]))id(n2),id(n3))print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")#打印修改後的k2的地址print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"]),"\n")try:#打印"k3"的ip地址 print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"]),"\n")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,"\n",new_dic)

    在上面,咱們使用copy模塊的deepcopy來進行處理,咱們知道,有不少信息,在嵌套中,只有deepcopy()纔會生成第二層的信息。

相關文章
相關標籤/搜索