1. 程式人生 > 其它 >圖解Python中深淺copy

圖解Python中深淺copy

在工作中,常涉及到資料的傳遞,在資料傳遞使用過程中,可能會發生資料被修改的問題。為了防止資料被修改,就需要在傳遞一個副本,即使副本被修改,也不會影響原資料的使用。為了生成這個副本,就產生了拷貝。今天就說一下Python中的深淺拷貝問題。

一、深淺copy

  1. 賦值運算

l1 = [1, 2, 3, [22, 33]]l2 = l1l1.append(666)print(l1)  # [1, 2, 3, [22, 33], 666]print(l2)#[1,2,3,[22,33],666]

圖解:

注意:l2 = l1是一個指向,是賦值,和深淺copy無關。

  1. 淺copy

其實列表是一個一個的槽位,每個槽位儲存的是該物件的記憶體地址

#例1. 給大列表新增元素l1 = [1, 2, 3, [22, 33]]l2 = l1.copy()# 或者下面這種方式,也是淺copy# import copy# l2 = copy.copy(l1)l1.append(666)
print(l1) # [1, 2, 3, [22, 33], 666]print(l2) # [1, 2, 3, [22, 33]]
#例2. 給小列表新增元素l1 = [1, 2, 3, [22, 33]]l2 = l1.copy()l1[-1].append(666)
print(l1) # [1, 2, 3, [22, 33, 666]]
print(l2) # [1, 2, 3, [22, 33, 666]]、
例3. 將l1列表中第一個元素改為6l1 = [1, 2, 3, [22, 33]]l2 = l1.copy()l1[0] = 6
print(l1) # [6, 2, 3, [22, 33]]print(l2)#[1,2,3,[22,33]]

圖解:

例1

例2

例3

小結:

淺copy:會在記憶體中新開闢一個空間,存放這個copy的列表,但是列表裡面的內容還是沿用之前物件的記憶體地址。

  1. 深copy

import copyl1 = [1, 2, 3, [22, 33]]l2 = copy.deepcopy(l1)
l1.append(666)print(l1) # [1, 2, 3, [22, 33], 666]print(l2)#[1,2,3,[22,33]]

圖解:

本質如下圖:

但是python對深copy做了一個優化,將可變的資料型別在記憶體中重新建立一份,而不可變的資料型別則沿用之前的,所以記憶體中是下面這樣的:

小結:

深copy:會在記憶體中開闢新空間,將原列表以及列表裡面的可變資料型別重新建立一份,不可變資料型別則沿用之前的。

為什麼Python預設的拷貝方式是淺拷貝?

  • 時間角度:淺拷貝花費時間更少。
  • 空間角度:淺拷貝花費記憶體更少。
  • 效率角度:淺拷貝只拷貝頂層資料,一般情況下比深拷貝效率高。

總結:

  • 不可變物件在賦值時會開闢新空間。
  • 可變物件在賦值時,修改一個的值,另一個也會發生改變。
  • 深、淺拷貝對不可變物件拷貝時,不開闢新空間,相當於賦值操作。
  • 淺拷貝在拷貝時,只拷貝第一層中的引用,如果元素是可變物件,並且被修改,那麼拷貝的物件也會發生變化。
  • 深拷貝在拷貝時,會逐層進行拷貝,直到所有的引用都是不可變物件為止。
  • Python 有多種方式實現淺拷貝,copy模組的copy 函式 ,物件的 copy 函式 ,工廠方法,切片等。
  • 大多數情況下,編寫程式時,都是使用淺拷貝,除非有特定的需求。
  • 淺拷貝的優點:拷貝速度快,佔用空間少,拷貝效率高。