1. 程式人生 > >賦值,淺拷貝,深拷貝

賦值,淺拷貝,深拷貝

怎麽 嘗試 world 賦值 app 第一個 code 以及 不可

一、賦值
str例
a=hello
b=hello
c=a
print(id(a),id(b),id(c))
#2518845789440 2518845789440 2518845789440

我們可以發現a,b,c三者的地址是一樣的。所以以上賦值的操作就相當於c=a=b=‘hello‘

賦值是系統先給一個變量或者對象分配了內存,然後再將地址賦給a,b,c。所以它們的地址是相同的

list例

a=[hello]
b=[hello]
c=a
print(id(a),id(b),id(c))
#1924016299912 1924016299976 1924016299912

但是這種情況卻不一樣了,a和b的地址不同,為什麽

因為str是不可變的,所以同樣是‘hello’只有一個地址,但是list是可變的,所以必須分配兩個地址

如果以上兩種情況修改了值會怎麽樣

str例

a=hello
b=hello
c=a
a=world
print(id(a),id(b),id(c))
#2570701091368 2570703634360 2570703634360

這時a的地址和值變量,但是b,c地址和值都未變。因為str的不可變性,a要重新復制則需要重新開辟內存空間,所以a的值改變,a指向的地址改變,b,c由於‘hello’的不可變性,不會發生改變

list例

a=[hello]
b=[hello]
c=a
a[0]=world
print(id(a),id(b),id(c))
#2476863774600 2476863774664 2476863774600

這時a,c的值和地址均改變,但二者仍相同,b不改變,由於list的可變性,所以修改list的值不需要另外開辟空間,只需修改原地址的值,所以a,c均改變

二、淺拷貝

1 a=[hello,[123,234]]
2 b=a[:]
3 print(id(a),id(b))
4 print(id(a[0]),id(a[1]))
5
print(id(b[0]),id(b[1])) 6 7 #2142142193608 2142142197896 8 #2142022964480 2142142193544 9 #2142022964480 2142142193544

我們可以看出a,b地址不同,這符合list是可變的,應開辟不同的空間,我們看第四行和第五行,發現元素的地址也是相同的。如果說字符串‘hello’地址一致還能理解,但是第二個元素的list地址仍一致。這就說明了淺拷貝的特點,只是將容器內的元素的地址復制了一份

接著我們嘗試修改a,b中的值

a=[hello,[123,234]]
b=a[:]

a[0]=world
a[1].append(345)
print(a)
print(b)

#[‘world‘, [123, 234, 345]]
#[‘hello‘, [123, 234, 345]]

a中第一個元素str改變,但是b中未改變,a中第二個元素改變,b中也改變,這就符合不可變的對象修改會開辟新的空間,可變的對象修改不會開辟新空間,也進一步證明了淺拷貝僅僅是復制了容器中元素的地址

三、深拷貝

from copy import deepcopy
a=[hello,[123,234]]
b=deepcopy(a)
print(id(a),id(b))
print(id(a[0]),id(a[1]))
print(id(b[0]),id(b[1]))

#2576042483656 2576042487944
#2575924887480 2576042483592
#2575924887480 2576042488136

深拷貝後,可以發現a,b地址以及a,b中元素地址均不同。這才是完全拷貝了一個副本

1 from copy import deepcopy
2 a=[hello,[123,234]]
3 b=deepcopy(a)
4 
5 a[0]=world
6 a[1].append(345)
7 print(a)
8 print(b)

#[‘world‘, [123, 234, 345]]
#[‘hello‘, [123, 234]]

從打印結果來看僅僅a修改了,b沒有任何修改。因為b是一個完全的副本,元素地址均與a不同,a修改,b不受影響

總結

1、賦值是將一個對象的地址賦值給一個變量,讓變量指向改地址

2、淺拷貝是在另一塊地址中創建一個新的變量或容器,但是容器內的元素的地址均是原對象的元素的地址的拷貝,也就是說新的容器中指向了舊的元素

3、深拷貝是在另一塊地址中創建一個新的變量或容器,同時容器內的元素的地址也是新開辟的,僅僅是值相同而已,是完全的副本

賦值,淺拷貝,深拷貝