Python 從入門到進階之路(七)

以前的文章咱們簡單介紹了一下 Python 中異常處理,本篇文章咱們來看一下 Python 中 is 和 == 的區別及深拷貝和淺拷貝。python

咱們先來看一下在 Python 中的雙等號 == 。緩存

== 是比較兩個對象的內容是否相等,即兩個對象的「值「」是否相等,無論二者在內存中的引用地址是否同樣。

is 比較的是兩個實例對象是否是徹底相同,它們是否是同一個對象,佔用的內存地址是否相同。即is比較兩個條件:1.內容相同。2.內存中地址相同

 1 a = 10000
 2 b = 10000
 3 print(a == b)  # True
 4 print(a is b)  # True
 5 print(id(a))  # 4461408208
 6 print(id(b))  # 4461408208
 7 
 8 a = "hello world"
 9 b = "hello world"
10 print(a == b)  # True
11 print(a is b)  # True
12 print(id(a))  # 4461408208
13 print(id(b))  # 4461408208
14 
15 a = [11,22,33]
16 b = [11,22,33]
17 print(a == b)  # True
18 print(a is b)  # False
19 print(id(a))  # 4409720712
20 print(id(b))  # 4409720776

在上面的代碼中,咱們分別定義了 a 和 b 兩個變量,經過輸出結果能夠發現當變量爲字符串或數字時, is 和 == 的輸出結果是同樣的,當爲列表時 is 和 == 結果不同,經過打印兩個變量的 id 值能夠看出兩個 id 值不同,這是因爲當咱們建立列表 a 和 b 時,是分別開闢了兩塊內存來分別存儲這兩個變量,從表象上來看結果是同樣的,但兩個變量所指向的內存地址不同,咱們將上面的代碼改成以下:編輯器

1 a = [11,22,33]
2 b = a
3 print(a == b)  # True
4 print(a is b)  # True
5 print(id(a))  # 4535062408
6 print(id(b))  # 4535062408

在上面的代碼中,咱們並無直接給變量 b 賦值,而是讓 b=a,這樣的話 b 和 a 就指向了同一塊內存,因此 a is b 就爲 True 了。函數

上面的代碼我是在 PyCharm 編輯器中實現的,可是在終端命令行實現的話結果倒是不同的,以下:優化

 1 >>> a = 10000
 2 >>> b = 10000
 3 >>> a == b
 4 True
 5 >>> a is b
 6 False
 7 >>> id(a)
 8 4360555120
 9 >>> id(b)
10 4360555216

當咱們將 a 和 b 的值變小時,以下:spa

 1 >>> a = 100
 2 >>> b = 100
 3 >>> a == b
 4 True
 5 >>> a is b
 6 True
 7 >>> id(a)
 8 4357367984
 9 >>> id(b)
10 4357367984

形成上面的緣由是由於python對小整數在內存中直接建立了一份,不會回收,全部建立的小整數變量直接從對象池中引用他便可。可是注意Python僅僅對比較小的整數對象進行緩存(範圍爲範圍[-5, 256])緩存起來,而並不是是全部整數對象。也就說只有在這個[-5,256]範圍內建立的變量值使用is比較時候纔會成立。命令行

在 PyCharm 中,當值超過 256 時 is 和 == 的輸出結果還是同樣,這是由於解釋器也作了一部分優化,對於數字和字符串這類變量都進行了緩存。code

咱們再來看一下在終端命令行中當變量爲字符串時:對象

 1 >>> a = "hello world"
 2 >>> b = "hello world"
 3 >>> a == b
 4 True
 5 >>> a is b
 6 False
 7 >>> id(a)
 8 4359747248
 9 >>> id(b)
10 4361247408
 1 >>> a = "hello"
 2 >>> b = "hello"
 3 >>> a == b
 4 True
 5 >>> a is b
 6 True
 7 >>> id(a)
 8 4361199040
 9 >>> id(b)
10 4361199040

經過輸出結果能夠看出,在命令行中當變量爲簡單字符串時輸出結果一致,不然輸出結果不一致,這是因爲 Python 對簡單字符串對象也進行了緩存,這樣作的意義是能夠優化代碼的運行速度,減小內存消耗。blog

 

在上面的代碼中,咱們讓 a=b 實際上是一種淺拷貝的過程,他們指向的是同一塊內存,當咱們改變其中一個變量時,另外一個也會變,以下:

1 a = [11,22,33]
2 b = a
3 a[0] = 123
4 print(a)  # [123, 22, 33]
5 print(b)  # [123, 22, 33]

在 Python 中海油深拷貝,它是從新開闢一塊區域用來存儲變量的,以下:

 1 import copy
 2 
 3 a = [11, 22, 33]
 4 b = a
 5 c = [11, 22, 33]
 6 d = copy.deepcopy(a)
 7 print(a == b, a is b)  # True True
 8 print(a == c, a is c)  # True False
 9 print(a == d, a is d)  # True False
10 
11 a[0] = 123
12 print(a)  # [123, 22, 33]
13 print(b)  # [123, 22, 33]
14 print(c)  # [11, 22, 33]
15 print(d)  # [11, 22, 33]

在上面的代碼中咱們引入了一個 copy 的模塊,引入模塊這個以前的文章沒有提到,後續會單獨說一下。

在 copy 模塊中有一個 deepcopy() 的方法,從上面的代碼中能夠看出 deepcopy() 的方法就至關於 c=[11,22,33] 這樣從新開闢一塊區域來存儲變量,當 a 變量改變時,淺拷貝的內容 b 會隨之改變,可是深拷貝的內容 d 並非指向 a 的內存地址,因此不會改變。

 

在 copy 的模塊中海油一個 copy() 方法,它在某些方面看起來和 deepcopy() 方法是同樣的,其實不同,以下:

import copy

a = [11, 22, 33]
b = copy.copy(a)
c = copy.deepcopy(a)
a[0] = 123
print(a)  # [123, 22, 33]
print(b)  # [11, 22, 33]
print(c)  # [11, 22, 33]

從上面的輸出結果看,當 a 變量修改以後,b 變量和 c 變量同樣沒有改變,那 copy() 和 deepcopy() 到底有什麼區別呢,咱們再看下面的代碼:

1 import copy
2 
3 a = [11, 22, [123,456]]
4 b = copy.copy(a)
5 c = copy.deepcopy(a)
6 a[2][0] = 789
7 print(a)  # [11, 22, [789, 456]]
8 print(b)  # [11, 22, [789, 456]]
9 print(c)  # [11, 22, [123, 456]]

從上面的輸出結果能夠看出,b 變量隨 a 變量的變化而變化了,而 c 變量沒有。

很顯然這時 copy() 函數拷貝的值隨着原對象的值修改了,而 deepcopy() 的值沒有隨着原對象的值修改。主要是由於 deepcopy()  會將複雜對象的每一層複製一個單獨的個體出來對於 copy() 函數要慎用,慎用。

相關文章
相關標籤/搜索