python怎麼避免淺拷貝?#技術派的書架#,我來為大家科普一下關于python怎麼避免淺拷貝?以下内容希望對你有幫助!
Python 附帶了一個名為 copy 的模塊,它提供了特定的複制功能。在本文中,我們将探索什麼是深拷貝和淺拷貝。此外,我們還将讨論它們之間的差異以及何時使用其中一種而不是另一種。
不可變對象 vs 可變對象
在進入 Python 中的淺拷貝和深拷貝之前,首先要理解可變對象類型和不可變對象類型之間的區别。顧名思義,不可變對象是不可以被修改的,因此,當這些對象的值被修改時,Python 會創建一個新的對象。
例如,假設我們有兩個變量引用同一個整數對象:
>>> a = 10
>>> b = a # variables a and b hold the reference to the same object
現在,如果我們對變量 a 執行任何類型的操作,并且考慮到 Python 中的整數是不可變的,那麼結果将會創建一個保存新值的新對象。這意味着對象的舊值(以及引用它的所有變量)将保持不變:
>>> a = a 1
>>> print(a)
11
>>> print(b)
10
另一方面,可變對象類型允許對對象值進行就地修改。這意味着,當修改可變對象類型的值時,保存對同一對象的引用的所有變量都會受到影響。例如,假設我們确實有以下列表
>>> list_1 = [1, 2, 3]
>>> list_2 = list_1
考慮到 Python 中的列表是可變的,如果我們改變這兩個列表中的任何一個,這個操作也會對其他變量産生直接影響,因為它們都指向内存中相同的對象引用。
>>> list_1[0] = 0
>>> print(list_1)
[0, 2, 3]
>>> print(list_2)
[0, 2, 3]
複制對象最直接的方法是通過常規的賦值操作。假設我們有一下操作:
a = [1, 2, 3]
b = a
在這種情況下,變量 a 和 b 對同一個對象都有相同的引用。這意味着,如果這兩個變量中的任何一個用于執行就地修改,其他變量也将受到影響。
>>> a[0] = 0
>>> print(a)
[0, 2, 3]
>>> print(b)
[0, 2, 3]
因此,當我們必須處理不可變的對象類型時,通常會使用常規的賦值操作。在這種情況下,當使用兩個變量中的任何一個執行操作時,另一個變量将保持不變,因為它的引用指向的是不變的舊對象。
>>> id(a) == id(b)
True
Python 中的賦值語句不複制對象,它們在目标和對象之間創建綁定。
淺拷貝 vs 深拷貝在深入讨論淺拷貝和深拷貝的細節之前,請注意,它們的區别隻有在我們必須處理本質上是嵌套結構的複合對象時才有意義。換句話說,複合對象是包含其他對象的對象,例如,列表列表或集合字典。
一個淺拷貝将獲得一個原始對象的副本并創建一個新的複合對象,但是如果我們正在複制的對象是一個複合對象,那麼内部對象将與在原始對象中找到的對象相同。
>>> import copy
>>> b = copy.copy(a)
>>> id(a) == id(b)
False
如我們所見,列表對象 a 和 b 是不同的,這意味着它們持有指向内存中不同對象的不同引用(即使這些對象的值相同)。
當我們需要處理複合對象時,事情會變得有點複雜。現在讓我們假設變量 a 是一個複合對象,它表示一個列表列表:
a = [[1, 2, 3], [4, 5, 6]]
現在讓我們對 a 進行淺拷貝:
>>> import copy
>>> b = copy.copy(a)
我們可以看到 a 和 b 是不同的對象:
>>> id(a) == id(b)
False
然而,内部對象(即兩個内部列表)與原始對象引用的對象相同:
>>> id(a[0]) == id(b[0])
True
這是非常危險的,因為任何内部列表的更改都會影響引用這些内部列表的其他複合對象:
>>> a[0][0] = 0
>>> a
[[0, 2, 3], [4, 5, 6]]
>>> b
[[0, 2, 3], [4, 5, 6]]
因此,隻有當我們不必處理複合對象時,淺拷貝才适用。
淺拷貝構造一個新的複合對象,然後(在可能的範圍内)将對原始對象中找到的對象的引用插入其中。
深層拷貝将獲取原始對象的副本,然後遞歸地獲取找到的内部對象的副本(如果有的話)。
>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.deepcopy(a)
同樣,我們可以看到原始對象和複制對象在本質上是不同的:
>>> id(a) == id(b)
False
但在這種情況下,即使是内部對象也會不同:
>>> id(a[0]) == id(b[0])
False
這意味着 a 中任何嵌套列表的更改都不會影響對象 b 中的相應列表:
>>> a[0][0] = 0
>>> a
[[0, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
因此,當我們必須處理複合對象并希望确保任何内部對象的更改都不會影響引用相同對象的其他變量時,深拷貝更為合适。
深拷貝構造一個新的複合對象,然後遞歸地将原始對象中找到的對象的副本插入其中。
總結在本文中,我們探讨了用 Python 複制對象的三種基本方法。最初,我們讨論了不可變對象類型和可變對象類型之間的區别。不需要複制不可變物件類型,因為這些實例的值永遠不會改變。另一方面,開發人員在修改可變對象類型時需要非常小心,因為這個操作可能會潛在地影響保存相同對象的引用的其他變量。當此類對象就地更改時,引用同一對象的所有其他變量也将受到此更改的影響。
因此,了解如何正确地複制可變對象以避免代碼中的 bug 非常重要。回想一下,一個淺拷貝将從原始對象中創建一個新對象,但是如果對象包含其他對象,那麼内部對象将不會被複制。另一方面,深度拷貝将為複合對象中包含的内部對象創建一個新對象。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!