成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

學習Python一年,這次終于弄懂了淺拷貝和深拷貝

開發 前端
Python中對象的賦值其實就是對象的引用。當創建一個對象,把它賦值給另一個變量的時候,Python并沒有拷貝這個對象,只是拷貝了這個對象的引用而已。

話說,網上已經有很多關于 Python 淺拷貝和深拷貝的文章了,不過好多文章看起來還是決定似懂非懂,所以決定用自己的理解來寫出這樣一篇文章。

當別人一提起Python中的復制操作,你會不會立馬站起來說:“我會”,于是就有了如下操作:

import copy

x = copy.copy(y) # 淺拷貝我會了
x = copy.deepcopy(y) # 深拷貝我來了

那淺拷貝和深拷貝有什么區別呢,你能給我講講嗎?

1、從引用vs.拷貝說起

首先,我們要弄清楚什么是對象引用與對象拷貝(復制)。

對象引用

Python中對象的賦值其實就是對象的引用。當創建一個對象,把它賦值給另一個變量的時候,Python并沒有拷貝這個對象,只是拷貝了這個對象的引用而已。

>>> a = 1
>>> b = a
>>> id(a) == id(b)
True
>>> x = [1, 2, 3]
>>> y = [x, 4]
>>> x
[1, 2, 3]
>>> y
[[1, 2, 3], 4]
>>>
>>>> id(x) == id(y)
False
>>> id(x) == id(y[0])
True

如果這個過程不理解,可以看看下圖:

圖片

當我們對 x 列表進行操作時,會發現 y 中也發生了意料之外的事情:

>>> x[1] = 2020
>>> y
[[1, 2020, 3], 4]

由于列表是可變的,修改x這個列表對象的時候,也會改變對象 y 中對 x 的引用。

所以當我們在原處修改可變對象時 可能會影響程序中其他地方對相同對象的其他引用,這一點很重要。如果你不想這樣做,就需要明確地告訴 Python 復制該對象。

對象拷貝

如果你需要拷貝,可以進行如下操作:

  • 沒有限制條件的分片表達式(L[:])
  • 工廠函數(如list/dir/set)
  • 字典copy方法(X.copy())
  • copy標準庫模塊(import copy)

舉個例子,假設有一個列表L和一個字典D:

>>> L = [2019, 2020, 2021]
>>> D = {'1':2019, '2':2020, '3':2021}
>>>
>>> A = L[:] # 區分 A=L 或 A = List(L)
>>> B = D.copy() # 區分 B=D
>>> A
[2019, 2020, 2021]
>>> B
{'1': 2019, '2': 2020, '3': 2021}

圖片

這樣定義之后,當你修改A和B時,會發現并不會對原來的L跟D產生影響,因為,這就是對象的拷貝。

>>> A[1] = 'happy'
>>> B[3] = 'today'
>>> L, D
([2019, 2020, 2021], {'1': 2019, '2': 2020, '3': 2021})
>>> A, B
([2019, 'happy', 2021], {'1': 2019, '2': 2020, '3': 2021, 3: 'today'})

上述對列表和字典的拷貝操作默認都為淺拷貝:

  • 制作字典的淺層復制可以使用dict.copy() 方法
  • 而制作列表的淺層復制可以通過賦值整個列表的切片完成,例如,copied_list = original_list[:]。

說到這里,疑問就產生了?什么是淺拷貝?淺拷貝的對應深拷貝又該作何解釋?

2、談談淺拷貝和深拷貝

官方文檔定義:

淺層復制和深層復制之間的區別僅與復合對象 (即包含其他對象的對象,如列表或類的實例) 相關:

一個淺層復制 會構造一個新的復合對象,然后(在可能的范圍內)將原對象中找到的 引用 插入其中。

一個深層復制 會構造一個新的復合對象,然后遞歸地將原始對象中所找到的對象的 副本 插入。

淺拷貝

?淺拷貝:拷貝了最外圍的對象本身,內部的元素都只是拷貝了一個引用而已。也就是,把對象復制一遍,但是該對象中引用的其他對象我不復制。

用通俗的話理解就是:你的櫥柜(對象)里裝著一??(籃子)??(雞蛋),然后淺拷貝一下的意思。我只拷貝了最外面的這個櫥柜,至于里面的內部元素(??和??)我并不拷貝。

當我們遇到簡單的對象時,用上面的解釋好像很好理解;如果遇到復合對象,就比如下列代碼:

l1 = [3, [66, 55, 44], (3, 7, 21)]
l2 = list(l1)
l1.append(100)
print('l1:', l1)
print('l2:', l2)
l1[1].remove(55)
l2[1] += [33, 22]
l2[2] += (9, 9, 81)
print('l1:', l1)
print('l2:', l2)

代碼解釋:

  • l2是l1的淺拷貝
  • 把100追加到l1,對l2沒有影響
  • 1內部列表l1[1中的55刪除,對l2也產生影響,因為l1[1]和l2[1]綁定的是同一個列表
  • 對可變對象來說,l2[1引用的列表進行+=就地修改列表。這次修改導致l1[1]也發生了改變
  • 對元組來說,+= 運算符創建一個新元組,然后重新綁定給變量 l2[2]。這等同于l2[2] = l2[2] + (10, 11)。現在,l1 和 l2 中最 后位置上的元組不是同一個對象

把這段代碼可視化出來如下:

圖片

動手試一試,可以點此處

深拷貝

?深拷貝:外圍和內部元素都進行了拷貝對象本身,而不是引用。也就是,把對象復制一遍,并且該對象中引用的其他對象我也復制。

對比上面的籃子和雞蛋:你的櫥柜(對象)里裝著一??(籃子)??(雞蛋),然后深拷貝一下的意思。把最外面的這個櫥柜和里面的內部元素(??和??)全部拷貝過來。

圖片

from copy import deepcopy
l1 = [3, [66, 55, 44], (3, 7, 21)]
l2 = deepcopy(l1)
l1.append(100)
print('l1:', l1)
print('l2:', l2)
l1[1].remove(55)
l2[1] += [33, 22]
l2[2] += (9, 9, 81)
print('l1:', l1)
print('l2:', l2)

輸出結果:

圖片

拷貝的特點

  1. 不可變類型的對象(如數字、字符串、和其他'原子'類型的對象)對于深淺拷貝毫無影響,最終的地址值和值都是相等的。也就是,"obj is copy.copy(obj)" 、"obj is copy.deepcopy(obj)"
  2. 可變類型的對象=淺拷貝:值相等,地址相等copy淺拷貝:值相等,地址不相等deepcopy深拷貝:值相等,地址不相等
  3. 循環引用的對象如果對象有循環引用,那么這個樸素的算法會進入無限循環。deepcopy 函數會記住已經復制的對象,因此能優雅地處理循環引用。

循環引用:b 引用 a,然后追加到 a 中;deepcopy 會想辦法復制 a,而copy會進入無限循環。如下面代碼:

from copy import deepcopy, copy
a = [80, 90]
b = [a, 100]
a.append(b)
print("a:", a)
print("b:", b)

c = deepcopy(a)
print("c:", c)

d = copy(b)
print("d:", d)

輸出結果:

a: [80, 90, [[...], 100]]
b: [[80, 90, [...]], 100]
c: [80, 90, [[...], 100]]
d: [[80, 90, [[...], 100]], 100]

深淺拷貝的作用

1,減少內存的使用2,以后在做數據的清洗、修改或者入庫的時候,對原數據進行復制一份,以防數據修改之后,找不到原數據。3. 可以定制復制行為,通過實現__copy()和__deep__()方法來控制。

3、總結

看完這篇文章后,轉身就跟你同桌說:“x同學,聽說你最近在學Python,你知道淺拷貝和深拷貝嗎?”“不知道,學得有點暈”“沒事,我來給你講講:”

拷貝其實在開始學好幾個操作語句中,我們就已經使用過卻可能不知道的(前3個),而且淺拷貝是Python的默認拷貝方式。拷貝的方法如下:

  1. 可變類型的切片操作:[:]
  2. 工廠函數(如list/dir/set)
  3. 字典copy方法(X.copy())
  4. 然后就是Python有專門的copy標準庫模塊:包含兩個方法copy()和deepcopy()

淺拷貝就像是我只拷貝最外圍的對象,對象中引用的其他對象我不復制。深拷貝就是完整的把對象和對象里的內容都拷貝過來。拷貝的目的:

  1. 為了節省內存
  2. 防止數據丟失。

后記:深淺拷貝的坑及難以理解的點也只在復合對象上,簡單對象就是我們平常理解的復制。而針對非容器類型(如數字、字符串、和其他'原子'類型的對象)沒有被拷貝一說。

要是你的同桌還是不懂,你就把這篇文章甩給他,讓他好好看看(偷笑)。如果你覺得這篇文章還不錯,請點個贊或者收個藏,點個關注更好啦。

責任編輯:武曉燕 來源: 宇宙之一粟
相關推薦

2021-09-27 11:07:11

深拷貝淺拷貝內存

2022-07-26 08:07:03

Python淺拷貝深拷貝

2021-07-16 12:33:24

Javascript深拷貝淺拷貝

2017-08-16 13:30:05

Java深拷貝淺拷貝

2023-09-22 12:21:33

Python深拷貝淺拷貝

2019-02-25 08:58:16

Python深拷貝淺拷貝

2020-06-23 08:41:47

JavaScript開發技術

2020-08-03 08:24:26

原型模式拷貝

2018-09-26 14:37:17

JavaScript前端編程語言

2021-01-08 06:15:09

深拷貝淺拷貝寫時拷貝

2023-05-17 08:42:46

深拷貝Golang

2009-05-19 17:28:44

深拷貝淺拷貝clone()

2021-09-10 07:41:06

Python拷貝Python基礎

2020-10-12 08:35:22

JavaScript

2024-03-15 15:03:23

2024-04-17 09:01:08

Python深拷貝淺拷貝

2018-05-10 14:20:18

前端JavaScript深拷貝

2023-05-17 07:36:00

淺拷貝深拷貝對象

2022-09-30 15:03:09

C語言深拷貝淺拷貝

2024-02-05 22:56:16

C++拷貝開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 性高湖久久久久久久久3小时 | 国产美女在线播放 | 亚洲a在线观看 | 日韩在线观看视频一区 | 欧美日韩国产精品一区二区 | 国产一区二区久久 | 男人久久天堂 | 最新一级毛片 | 亚洲三级在线观看 | 免费天天干 | 伊人久久一区二区 | 日韩伦理一区二区三区 | 久久久久久中文字幕 | www.夜夜骑.com | 中文字幕av亚洲精品一部二部 | 亚洲精选一区 | 亚洲精品久久久久久宅男 | 91免费小视频 | 97av视频| 91传媒在线观看 | 久久久久久国产 | 一区观看 | 色精品视频 | 欧美久久久久 | 日韩欧美视频在线 | 欧美成年黄网站色视频 | 免费在线日韩 | www国产精 | 欧美中文字幕在线 | 伊人手机在线视频 | yeyeav| 久久不卡| 久久男人| 盗摄精品av一区二区三区 | 免费看av大片 | 一级片在线视频 | 91久久久精品国产一区二区蜜臀 | 精品一区二区三区在线视频 | 国产精品高清一区二区三区 | 亚洲国产精品久久久 | 国精日本亚洲欧州国产中文久久 |