Python對象的深淺拷貝,你到底變不變

  • 2020 年 4 月 11 日
  • 筆記

在Python有個重要的東西,就是對象的深淺拷貝。

我們就稱為:'==' vs 'is'

  • == 比較對象之間的值是否相等
  • is 比較的是對象身份是否相等,它們是否同一個對象

我們一般通過id來是否相等來判斷是否同一個對象

a = 10  b = 10    a == b  True    id(a)  4427562448    id(b)  4427562448    a is b  True

注意a is b == True 只適合和用於-5 到256之間,這個不知道你是否知道,我覺得面試官肯定不知道。

a = 257  b = 257    a == b  True    id(a)  4473417552    id(b)  4473417584    a is b  False

下面我們說下,淺拷貝和深拷貝

l1 = [1, 2, 3]  l2 = list(l1)    l2  [1, 2, 3]    l1 == l2  True    l1 is l2  False    s1 = set([1, 2, 3])  s2 = set(s1)    s2  {1, 2, 3}    s1 == s2  True    s1 is s2  False

淺拷貝指重新分配一塊記憶體,l2 就是l1的淺拷貝,但是只要是序列的淺拷貝,他們的id就是不一樣的。

對於深拷貝,在python中提供了對應的函數copy.copy()

import copy  l1 = [1, 2, 3]  l2 = copy.copy(l1)
t1 = (1, 2, 3)  t2 = tuple(t1)    t1 == t2  True    t1 is t2  True

元組(1,2,3)只被創建一次,t1和t2同時指向這個元組,反正你看到copy.copy()就是兩個True

這裡有一個天天來騙小孩的東西,就是l1變了,l2變不變的問題

我這裡在使用的嵌套列表

l1 = [[1, 2], (30, 40)]  l2 = list(l1)    l2  [[1, 2], (30, 40)]    l1.append(100)  l1[0].append(3)    l1  [[1, 2, 3], (30, 40), 100]    l2  [[1, 2, 3], (30, 40)]

l2竟然變了,這是為什麼。首先初始化一個列表l1,裡面的元素是一個列表和元組,然後對l1執行淺拷貝,賦予了l2 ,但是l2中的元素和l1指向同一個列表和元組對象,只有列表對象變,你淺拷貝就要跟著我變。

如果你添加一個序列來,我淺拷貝沒有指向你新來的對象。我幹嘛跟著你變。

l1.append(100)l1的列表新增元素100,不會對l2產生影響,l1和l2是兩個不同的對象

如果我在元組加呢???

l1[1] += (50, 60)    l1  [[1, 2, 3], (30, 40, 50, 60), 100]    l2  [[1, 2, 3], (30, 40)]

竟然不會變,說白了只有列表對象變,難道元組不可變你不知道?

深度拷貝

深度拷貝,就是你愛怎麼變,就去哪裡變,我就不變了。

import copy  l1 = [[1, 2], (30, 40)]  l2 = copy.deepcopy(l1)  l1.append(100)  l1[0].append(3)    l1  [[1, 2, 3], (30, 40), 100]    l2  [[1, 2], (30, 40)]

因為此時l1和l2完全獨立了,沒有任何影響

總結起來其實就是兩句話

  • 淺拷貝,不可變的不可變,可變的依舊可變
  • 深拷貝,都不可變