python淺拷貝與深拷貝使用方法詳解

淺拷貝和深拷貝在面試和日常的開發中都會經常遇到

我們就從 對象賦值、淺拷貝、深拷貝 三個方面來講

一、對象賦值

In [1]:
list1 = [1, 2, ['a', 'b']]
list2 = list1
print(list1)
print(list2)
[1, 2, ['a', 'b']]
[1, 2, ['a', 'b']]
In [2]:
list1[0] = 3
print(list1)
print(list2)
[3, 2, ['a', 'b']]
[3, 2, ['a', 'b']]
In [3]:
list2[1]=[1,2]
print(list1)
print(list2)
[3, [1, 2], ['a', 'b']]
[3, [1, 2], ['a', 'b']]
In [4]:
print(id(list1))
print(id(list2))
1742901832264
1742901832264

結論:直接對象賦值,兩個對象的地址是一樣的,也就是這兩個變量指向是同一個對象,兩個變量會同步變化

二、淺拷貝

In [5]:
import copy
A = [1, 'a', ['a', 'b']]
# B = A.copy() # 淺拷貝
B = copy.copy(A) # 淺拷貝
print(A)
print(B)
print(id(A))
print(id(B))
[1, 'a', ['a', 'b']]
[1, 'a', ['a', 'b']]
1742901926344
1742901925512
兩個對象的內存地址不一樣,也就是不是同一個對象
In [6]:
# 循環分別打印每個對象中的成員的地址
# 打印A
for i in A:
    print("值 {} 的地址是:{}".format(i,id(i)))
值 1 的地址是:140724000563600
值 a 的地址是:1742860054320
值 ['a', 'b'] 的地址是:1742901889800
In [7]:
# 循環分別打印每個對象中的成員的地址
# 打印B
for i in B:
    print("值 {} 的地址是:{}".format(i,id(i)))
值 1 的地址是:140724000563600
值 a 的地址是:1742860054320
值 ['a', 'b'] 的地址是:1742901889800

int類型的1和字符串型的a都是不可變數據類型,不可變數據類型值一樣,地址一樣,值不一樣,地址就不一樣

列表[‘a’, ‘b’]是可變數據類型,可變數據類型是 變量中數據變的時候,地址不會變,值相同的兩個對象,地址是不一樣的,如果地址一樣,表示指的是同一個對象

現在 A[2] 和 B[2] 指向的是同一個地址,說明是同一個列表,一個改變,另外的一個也會同步改變

通常來講不可變元素包含:

int,float,complex,long,str,unicode,tuple

In [8]:
# 在 A[2] 中增加元素
A[2].append(3)
print(A)
print(B)
[1, 'a', ['a', 'b', 3]]
[1, 'a', ['a', 'b', 3]]
In [9]:
# 向A中增加元素
A.append(3)
print(A)
print(B)
[1, 'a', ['a', 'b', 3], 3]
[1, 'a', ['a', 'b', 3]]
In [10]:
A[0]=2
print(A)
print(B)
[2, 'a', ['a', 'b', 3], 3]
[1, 'a', ['a', 'b', 3]]

淺拷貝(copy.copy()):拷貝父對象,不會拷貝對象的內部的子對象,也就是子對象共用

如果子對象是不可變數據類型,那麼復制的對象和原來的對象互不影響

如果是可變數據類型,那麼復制的對象和原來的對象共用

In [11]:
A[2]=[1,2]
print(A)
print(B)
[2, 'a', [1, 2], 3]
[1, 'a', ['a', 'b', 3]]
In [12]:
print(id(A[2]))
print(id(B[2]))
1742901889416
1742901889800

可以看到 現在 A[2] 和 B[2] 的地址不一樣瞭,那麼他們就互不影響瞭

其實看兩個可變數據類型是否互相影響,就是看他們的地址是否一樣

三、深拷貝

In [13]:
m = [1, 'a', ['a', 'b']]
n = copy.deepcopy(m)
print(m)
print(n)
print(id(m))
print(id(n))
[1, 'a', ['a', 'b']]
[1, 'a', ['a', 'b']]
1742900283720
1742900260680
In [14]:
# 循環分別打印每個對象中的成員的地址
# 打印m
for i in m:
    print("值 {} 的地址是:{}".format(i,id(i)))
值 1 的地址是:140724000563600
值 a 的地址是:1742860054320
值 ['a', 'b'] 的地址是:1742900341320
In [15]:
# 循環分別打印每個對象中的成員的地址
# 打印n
for i in n:
    print("值 {} 的地址是:{}".format(i,id(i)))
值 1 的地址是:140724000563600
值 a 的地址是:1742860054320
值 ['a', 'b'] 的地址是:1742900283208

可以看到,m和n兩個對象本身的地址是不一樣的,

並且m和n中成員中的可變數據類型的地址也是不一樣的,所以它們兩個是完全互不影響的

'''
學習中遇到問題沒人解答?小編創建瞭一個Python學習交流群:711312441
尋找有志同道合的小夥伴,互幫互助,群裡還有不錯的視頻學習教程和PDF電子書!
'''
In [16]:
m[2].append(3)
n[1]=5
print(m)
print(n)
[1, 'a', ['a', 'b', 3]]
[1, 5, ['a', 'b']]

淺拷貝(copy.copy()):拷貝父對象,不會拷貝對象的內部的子對象,也就是子對象共用

  • 如果子對象是不可變數據類型,那麼復制的對象和原來的對象互不影響
  • 如果是可變數據類型,那麼復制的對象和原來的對象共用

深拷貝(copy.deepcopy()):完全拷貝父對象跟子對象,復制的對象和原來的對象互不相關

四、深入解析

1、b = a.copy(): 淺拷貝, a 和 b 是一個獨立的對象,但他們的子對象還是指向統一對象(是引用)。

2、b = copy.deepcopy(a): 深度拷貝, a 和 b 完全拷貝瞭父對象及其子對象,兩者是完全獨立的。

到此這篇關於python淺拷貝與深拷貝使用方法詳解的文章就介紹到這瞭,更多相關python淺拷貝與深拷貝內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: