日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python的浅拷贝和深拷贝

發布時間:2025/3/20 python 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python的浅拷贝和深拷贝 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

相對于其他傳統編程語言,Python有一個比較奇怪的特性,即在復制對象時,有淺拷貝(shallow copy)和深拷貝(deep copy)兩種方式。

淺拷貝和深拷貝只和復合對象相關。復合對象指的是包含對象的對象,如列表(list)、類實例(class instance)等。簡單類型的對象(int、float、string等)不存在淺拷貝和深拷貝的說法。

看下面的實例:

colours1 = ["red", "blue"] colours2 = colours1 print(colours1) print(colours2) print(id(colours1), id(colours2))

輸出結果:

['red', 'blue'] ['red', 'blue'] 563841065096 563841065096

在上面的例子中,列表colours1被賦值給colours2。Colours1這樣的列表一般被稱為淺列表或普通列表,因為它只包含一些簡單數據類型,不包含嵌套結構,即不是嵌套列表。id()函數的值相同表明colours2和colours1這2個列表指向同一個對象,說明colours1被賦值給colours2時,并沒有分配新的內存地址,而是將colours2指向了colours1的內存地址。下圖給出了相關的數據結構說明。

現在我們看看分配一個新的列表對象給colours2,會發生什么?

colours2 = ["rouge", "vert"] print(colours1) print(colours2) print(id(colours1), id(colours2))

輸出結果:

['red', 'blue'] ['rouge', 'vert'] 357368848712 357368848456

跟我們期望的一樣,colours1的值保持不變,一個新的內存地址被分配給了colours2。
下面我們再看看colours2不是重新分配對象,而是改變其中一個元素的值,結果會有什么變化?

colours1 = ["red", "blue"] colours2 = colours1 print(id(colours1), id(colours2)) colours2[1] = "green" print(id(colours1), id(colours2)) print(colours1) print(colours2)

輸出結果:

1026592727752 1026592727752 1026592727752 1026592727752 ['red', 'green'] ['red', 'green']

可以看到,當我們將colours2中的第二個元素重新賦值時,colours1中的值也被自動改變了,很多初學者在這里都非常迷惑。事實上我們并沒有分配一個新的對象給colours2。colours1和colours2仍然指向同一個列表對象。即我們沒有兩個列表,仍然只有1個,只不過有2個名字。

那對于簡單列表,有沒有完全拷貝的方案呢,有!那就是使用切片方法。因為切片方法是重新生成了一個新對象。

list1 = ['a', 'b', 'c', 'd'] list2 = list1[:] list2[1] = 'x' print(list2) print(list1)

輸出結果:

['a', 'x', 'c', 'd'] ['a', 'b', 'c', 'd']

但是,如果是像下面這樣的嵌套列表,就又會遇到新的困難和問題。因為切片操作本質上仍然是淺拷貝。當遇到嵌套列表時,切片方法只復制子列表的地址,而不是其全部內容。

lst1 = ['a', 'b', ['ab', 'ba']] lst2 = lst1[:]

下面的圖給出了lst1和lst2的數據結構描述,lst2雖然是一個新建對象,但其中的子列表[‘ab’,’ba’]與lst1中的指的是同一個對象。

如果對lst1和lst2中的第一個元素或第二個元素進行賦值,并沒有什么副作用(side effect)

lst1 = ['a', 'b', ['ab', 'ba']] lst2 = lst1[:] lst2[0] = 'c' print(lst1) print(lst2)

輸出結果:

['a', 'b', ['ab', 'ba']] ['c', 'b', ['ab', 'ba']]


但是,如果改變的是嵌套子列表中的值,那么情況就發生了變化。

lst2[2][1] = 'd' print(lst1) print(lst2)

輸出結果:

['a', 'b', ['ab', 'd']] ['c', 'b', ['ab', 'd']]

下面的圖給出了為什么lst1中的嵌套子列表會跟隨lst2發生變化的原因,因為lst1和lst2的嵌套子列表指向同一個對象。

一個解決方案是使用標準庫的copy模塊。如果我們需要讓一個對象發生改變時不對原對象產生副作用,就需要一份這個對象的深度拷貝。深拷貝不僅僅拷貝了原始對象自身,也對其包含的值進行拷貝,它會遞歸的查找對象中包含的其他對象的引用,來完成更深層次拷貝。因此,深拷貝產生的副本可以隨意修改而不需要擔心會引起源對象的改變。

對先前的例子使用深拷貝:

from copy import deepcopy lst1 = ['a', 'b', ['ab', 'ba']] lst2 = deepcopy(lst1) print(lst1) print(lst2) print(id(lst1)) print(id(lst2)) print(id(lst1[0])) print(id(lst2[0])) print(id(lst1[2])) print(id(lst2[2]))

輸出結果:

['a', 'b', ['ab', 'ba']] ['a', 'b', ['ab', 'ba']] 537508176136 537508176200 537506121184 537506121184 537508176712 537508176776

可以看出lst1和lst2的嵌套子列表的內存地址不一樣了。下面的圖給出了deepcopy后的數據結構情形:

看看改變lst2中相關值的結果:

lst2[2][1] = "d" lst2[0] = "c" print(lst1) print(lst2)

輸出結果:

['a', 'b', ['ab', 'ba']] ['c', 'b', ['ab', 'd']]

上面的代碼最后將數據結構變成了這樣:

至于Python中為什么要有淺拷貝和深拷貝的區別,主要是出于效率方面的考慮。

參考文獻:http://www.python-course.eu/python3_deep_copy.php

總結

以上是生活随笔為你收集整理的Python的浅拷贝和深拷贝的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。