認清Python下==和is的區別

諾克大叔發表於2018-06-13

通常在Python語言中我們判斷兩個字串是否相等的時候,很多同學在初學Python的時候會混用==is,最後造成的結果就是出錯的時候不知道怎麼定位,結果也讓自己意向不到。

下面我們先來看一下==is的表現:

>>> a = 'hello'
>>> b = 'hello'
>>> a is b
True
>>> a == b
True
>>> # 如上情況 is 和 == 的結果一致

>>> a1 = "I'm a long string for code testing"
>>> b1 = "I'm a long string for code testing"
>>> a1 is b1    
False
>>> a1 == b1
True
>>> # 如上情況 is 和 == 結果不一致

>>> str1 = "string"
>>> str2 = "".join(['s', 't', 'r', 'i', 'n', 'g'])
>>> str2
'string'
>>> str1 is str2
False
>>> str1 == str2
True
>>> # 如上情況 is 和 == 結果不一致
複製程式碼

為什麼會出現這種情況呢?為什麼在有些情況下is==輸出結果相同有些情況又不同呢?我們簡單做如下分析: 首先通過id()函式來看看這些變數在記憶體中的具體儲存空間,整理情況如下:

認清Python下==和is的區別

從上圖表格中我們可以看出來is==在驗證兩個字串是否相等的時候表現是不一致的,顯然如果你混用或者誤認為他們是等同的那是存在風險的。

那麼字串的比較到底是用is還是==呢,我們來看一下Python官方文件中對兩種操作的說明:

Operation Syntax Function
Identity a is b is_(a, b)
Equality a == b eq(a, b)

從上可知is表示的是識別符號(Identity),而==表示的意思是相等(Equality),顯然兩者不是一個東西。

實際上造成上面輸出結果不一致的根本原因在於is的作用在於用來檢查物件的識別符號是否一致,也就是說is是比較兩個物件在記憶體中是否擁有同一塊記憶體空間,它並不適合來判斷兩個字串是否相等。a is b僅當a和b是同一個物件的時候才返回True, 所以a is b基本上相當於id(a) == id(b)。

==才是真正用來判斷兩個物件的值是否相等的,它實際呼叫的是builtins.py中的__eq__()方法,因此a == b相當於a.__eq__()b, 所以 == 操作符可以被過載,而 is 是不能被過載的。

一般情況下如果a is b為True的話a == b的值也是True,反之則亦然。 特殊情況除外,如下所示:

>>> a = float('NaN')
>>> a is a
True
>>> a == a
False
複製程式碼

從上面的介紹弄清楚了is==的區別之後,我們再來看圖示表格中的輸出就不難理解了。細心點的同學可能會發現,在表格中a和b的id值一樣,也就是說他們在同一記憶體空間地址中,而a1和b1的id值卻不一樣,這是為什麼呢?這是因為Python中string interning(字串駐留)機制所決定的: 相對於較小的字串,Python為了提高效能會保留其值的一個副本,當你再次建立這個字串的時候,直接就指向了這個副本,所以'hello'這個字串是在記憶體中有一個副本的,所以a和b的id的值是一樣的;而a1和b1是長字串,並不會駐留,Python在記憶體中分別為a1和b1建立了一個記憶體物件來標識a1和b1,所以這兩個物件擁有相同的內容但是識別符號是不一樣的,所以==的值為True而is的值為False。

所以最後總結一下,在Python裡面你要判斷兩個物件是否相等你應該使用==而不是is。

認清Python下==和is的區別

相關文章