本文目錄一覽:
- 1、python 為什麼有深拷貝淺拷貝
- 2、深拷貝和淺拷貝的區別是什麼?
- 3、Python中的賦值,淺拷貝和深拷貝的區別
- 4、python深拷貝和淺拷貝的區別
- 5、python 深copy和淺copy問題
python 為什麼有深拷貝淺拷貝
在寫Python過程中,經常會遇到對象的拷貝,如果不理解淺拷貝和深拷貝的概念,你的代碼就可能出現一些問題。所以,在這裡按個人的理解談談它們之間的區別。
一、賦值(assignment)
在《Python FAQ1》一文中,對賦值已經講的很清楚了,關鍵要理解變數與對象的關係。
12345
a = [1, 2, 3] b = a print(id(a), id(b), sep=’\n’)139701469405552139701469405552
在Python中,用一個變數給另一個變數賦值,其實就是給當前內存中的對象增加一個「標籤」而已。
如上例,通過使用內置函數 id() ,可以看出 a 和 b 指向內存中同一個對象。a is b會返回 True 。
二、淺拷貝(shallow copy)
注意:淺拷貝和深拷貝的不同僅僅是對組合對象來說,所謂的組合對象就是包含了其它對象的對象,如列表,類實例。而對於數字、字元串以及其它「原子」類型,沒有拷貝一說,產生的都是原對象的引用。
所謂「淺拷貝」,是指創建一個新的對象,其內容是原對象中元素的引用。(拷貝組合對象,不拷貝子對象)
常見的淺拷貝有:切片操作、工廠函數、對象的copy()方法、copy模塊中的copy函數。
12345678910
a = [1, 2, 3] b = list(a) print(id(a), id(b)) # a和b身份不同140601785066200 140601784764968 for x, y in zip(a, b): # 但它們包含的子對象身份相同… print(id(x), id(y))… 140601911441984 140601911441984140601911442016 140601911442016140601911442048 140601911442048
從上面可以明顯的看出來,a 淺拷貝得到 b,a 和 b 指向內存中不同的 list 對象,但它們的元素卻指向相同的 int 對象。這就是淺拷貝!
三、深拷貝(deep copy)
所謂「深拷貝」,是指創建一個新的對象,然後遞歸的拷貝原對象所包含的子對象。深拷貝出來的對象與原對象沒有任何關聯。
深拷貝只有一種方式:copy模塊中的deepcopy函數。
1234567891011
import copy a = [1, 2, 3] b = copy.deepcopy(a) print(id(a), id(b))140601785065840 140601785066200 for x, y in zip(a, b):… print(id(x), id(y))… 140601911441984 140601911441984140601911442016 140601911442016140601911442048 140601911442048
看了上面的例子,有人可能會疑惑:
為什麼使用了深拷貝,a和b中元素的id還是一樣呢?
答:這是因為對於不可變對象,當需要一個新的對象時,python可能會返回已經存在的某個類型和值都一致的對象的引用。而且這種機制並不會影響 a 和 b 的相互獨立性,因為當兩個元素指向同一個不可變對象時,對其中一個賦值不會影響另外一個。
我們可以用一個包含可變對象的列表來確切地展示「淺拷貝」與「深拷貝」的區別:
1234567891011121314151617181920
import copy a = [[1, 2],[5, 6], [8, 9]] b = copy.copy(a) # 淺拷貝得到b c = copy.deepcopy(a) # 深拷貝得到c print(id(a), id(b)) # a 和 b 不同139832578518984 139832578335520 for x, y in zip(a, b): # a 和 b 的子對象相同… print(id(x), id(y))… 139832578622816 139832578622816139832578622672 139832578622672139832578623104 139832578623104 print(id(a), id(c)) # a 和 c 不同139832578518984 139832578622456 for x, y in zip(a, c): # a 和 c 的子對象也不同… print(id(x), id(y))… 139832578622816 139832578621520139832578622672 139832578518912139832578623104 139832578623392
從這個例子中可以清晰地看出淺拷貝與深拷貝地區別。
總結:
1、賦值:簡單地拷貝對象的引用,兩個對象的id相同。
2、淺拷貝:創建一個新的組合對象,這個新對象與原對象共享內存中的子對象。
3、深拷貝:創建一個新的組合對象,同時遞歸地拷貝所有子對象,新的組合對象與原對象沒有任何關聯。雖然實際上會共享不可變的子對象,但不影響它們的相互獨立性。
淺拷貝和深拷貝的不同僅僅是對組合對象來說,所謂的組合對象就是包含了其它對象的對象,如列表,類實例。而對於數字、字元串以及其它「原子」類型,沒有拷貝一說,產生的都是原對象的引用。
深拷貝和淺拷貝的區別是什麼?
深拷貝和淺拷貝的區別如下:
淺拷貝(shallowCopy)只是增加了一個指針指向已存在的內存地址。
深拷貝(deepCopy)是增加了一個指針並且申請了一個新的內存,使這個增加的指針指向這個新的內存,使用深拷貝的情況下,釋放內存的時候不會因為出現淺拷貝時釋放同一個內存的錯誤。
Python的語句:
不同於C+ +等編程語言。Python的語句末尾不需要加分號表示語句結束,直接換行即可。
另外很重要的一點,就是使用縮進表示語句塊之間的邏輯關係,而不用大括弧。這兩個特點既保持代碼可讀性,又減少符號輸入提高效率。
一個語法上自成體系的單位,它由一個詞或句法上有關連的一組詞構成,表達一種主張、疑問、命令、願望或感嘆。當語句數超過一條時, 需要採用語句塊。
語句塊就是由塊標識符begin-end或fork-join界定的一組行為描述語旬。語句塊就相當於給塊中的一組行為描述語句進行打包,使之在形式上類似於一條語詢。語句塊的具體功能是通過語句塊中所包含的描述語句的執行而得以實現的。
當語句塊中只包含一條語句時,可以直接寫這條語句,此時塊標識符可以預設。語句塊包括串列語句塊(begin-end) 和並行語句塊(fork-join) 兩種。
Python中的賦值,淺拷貝和深拷貝的區別
賦值(=),就是創建了對象的一個新的引用,修改其中任意一個變數都會影響到另一個。
淺拷貝:創建一個新的對象,但它包含的是對原始對象中包含項的引用(如果用引用的方式修改其中一個對象,另外一個也會修改改變){1,完全切片方法;2,工廠函數,如list();3,copy模塊的copy()函數}
深拷貝:創建一個新的對象,並且遞歸的複製它所包含的對象(修改其中一個,另外一個不會改變){copy模塊的deep.deepcopy()函數}
python深拷貝和淺拷貝的區別
深度拷貝,就是把拷貝對象里所有的東西全部另存一份到新的內存空間,拷貝完後,兩者毫無聯繫,從此是路人。跟我們的常識理解是一回事。
淺拷貝,就是把拷貝對象的地址給了需要拷貝的對象,看上去兩個是不同的對象,其實本質都是一回事,也有另外一種淺拷貝,看上去,確實複製了一份新的,但這個新的對象,是個可變對象,它指向的對象內容,仍然沒有複製過來,仍然指向了同一個東西。
python 深copy和淺copy問題
利用切片操作方法拷貝就叫淺拷貝,只是拷貝了最外圍的對象本身,內部的元素都只是拷貝了一個引用而已。
利用copy中的deepcopy方法進行拷貝就叫做深拷貝,外圍和內部元素都進行了拷貝對象本身,而不是引用。
但是對於數字,字元串和其他原子類型對象等,沒有被拷貝的說法,即便是用深拷貝,查看id的話也是一樣的,如果對其重新賦值,也只是新創建一個對象,替換掉舊的而已。
引用:
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/271932.html