深拷貝與淺拷貝:Python對象複製的基礎方法

在Python中,當我們需要複製一個對象時,常常會遇到“賦值”“淺拷貝”和“深拷貝”這三種不同的操作。它們的行爲差異直接影響到對象複製後的獨立性,尤其是在處理嵌套的可變對象(如列表、字典等)時,理解它們的區別至關重要。

1. 賦值操作:只是“貼標籤”,不復制對象本身

在Python中,當我們將一個變量賦值給另一個變量時,本質上是讓新變量指向原對象的引用,而非創建一個新對象。此時,兩個變量會共享同一個對象,修改其中一個變量指向的對象內容,另一個變量也會受到影響。

示例:

a = [1, 2, 3]  # 列表a是一個可變對象
b = a          # b和a指向同一個列表對象
b.append(4)    # 修改b的內容(添加元素4)

print(a)  # 輸出:[1, 2, 3, 4],a也被修改了!

原因:列表是可變對象,b.append(4)會直接修改原列表,而ab只是同一個對象的不同“標籤”。

2. 淺拷貝:複製外層,內層“共享”原對象

淺拷貝(Shallow Copy)會創建一個新對象,但只複製對象的最外層元素,內層的嵌套對象(如列表中的列表、字典中的字典等)仍會引用原對象。因此,修改內層嵌套對象時,原對象也會受到影響。

實現方式:使用copy.copy()函數,或列表的切片[:]、字典的copy()方法。

示例:

import copy

a = [[1, 2], [3, 4]]  # 外層是列表,內層也是列表(嵌套結構)
b = copy.copy(a)      # 淺拷貝:外層創建新列表,但內層列表仍指向原對象

# 修改內層列表的第一個元素
b[0].append(5)  

print(a)  # 輸出:[[1, 2, 5], [3, 4]],原列表的內層列表被修改了!

原因:淺拷貝只複製了外層列表[ [1,2], [3,4] ],但內層的子列表[1,2][3,4]仍是原對象,修改b[0]會直接影響原列表a的子列表。

3. 深拷貝:遞歸複製所有層級,完全獨立

深拷貝(Deep Copy)會遞歸地複製所有層級的對象,包括嵌套的子對象。它會創建一個與原對象完全獨立的新副本,無論修改外層還是內層對象,原對象都不會受到影響。

實現方式:使用copy.deepcopy()函數。

示例:

import copy

a = [[1, 2], [3, 4]]  # 嵌套列表
b = copy.deepcopy(a)  # 深拷貝:複製所有層級的對象

# 修改內層列表的第一個元素
b[0].append(5)  

print(a)  # 輸出:[[1, 2], [3, 4]],原列表不受影響!

原因:深拷貝不僅複製了外層列表[ [1,2], [3,4] ],還遞歸複製了內層的子列表[1,2][3,4],因此ba是完全獨立的兩個對象。

如何選擇複製方式?

複製類型 適用場景 關鍵點
賦值(= 簡單不可變對象(如intstr 僅共享引用,修改可能影響原對象
淺拷貝(copy.copy() 單層嵌套的可變對象(如列表套元組) 僅複製外層,內層嵌套對象共享原對象
深拷貝(copy.deepcopy() 多層嵌套的可變對象(如列表套列表) 完全獨立,所有層級對象均複製

常見誤區總結

  1. 對不可變對象的誤解:對於intstr等不可變對象,賦值、淺拷貝、深拷貝效果類似,因爲修改不可變對象會創建新對象,不會影響原對象。
  2. 混淆淺拷貝和深拷貝:淺拷貝只能處理“一層嵌套”,深拷貝才能處理“所有層級嵌套”。
  3. 忽略嵌套結構:若對象包含嵌套可變對象(如[ [1], [2] ]),必須用深拷貝才能保證完全獨立。

總結

  • 賦值:共享引用,修改影響原對象(僅適用於簡單場景)。
  • 淺拷貝:複製外層,內層共享原對象(適用於單層嵌套)。
  • 深拷貝:遞歸複製所有層級,完全獨立(適用於多層嵌套)。

理解三者的區別,能幫助你在處理複雜數據結構時避免意外修改原對象,寫出更可靠的代碼。

小夜