Python - is vs == 的差異詳解
在 Python 程式碼中,我們經常需要比較兩個物件。這時你會面臨兩個選擇:== 運算子與 is 運算子。對於初學者來說,這兩者看起來似乎在做同樣的事情,但在 Python 的底層機制中,它們代表了完全不同的概念:「相等性 (Equality)」與「同一性 (Identity)」。
簡單來說:
==比較的是物件的內容(值)。is比較的是物件的記憶體位址(身分)。
== (Equality):值是否相等?
當你使用 == 時,你是在問:「這兩個物件裡面的資料長得一樣嗎?」
Python 在執行 == 比較時,實際上是呼叫了物件的 __eq__() 魔術方法。只要兩個物件的內容一致,結果就是 True。1
2
3
4list1 = [1, 2, 3]
list2 = [1, 2, 3]
print(list1 == list2) # True,因為內容完全一樣
is (Identity):是不是同一個物件?
當你使用 is 時,你是在問:「這兩個變數是不是指向記憶體中同一個位址?」
你可以把 is 想成是比較兩個物件的 id()。如果 id(a) == id(b),那麼 a is b 就會是 True。1
2
3
4list1 = [1, 2, 3]
list2 = [1, 2, 3]
print(list1 is list2) # False,因為它們是存放在不同位置的兩個獨立列表
如果我們讓一個變數指向另一個變數:1
2list3 = list1
print(list1 is list3) # True,因為 list3 只是 list1 的別名,指向同一個位址
為什麼 None 總是用 is?
在 Python 的慣例(PEP 8)中,檢查一個變數是否為 None 時,永遠應該使用 is None 而非 == None。1
2if x is None:
pass
為什麼?
- 效能:
is只是比較指標,速度極快。 - 安全:
None在 Python 中是一個單例 (Singleton) 物件。==可能會因為物件自定義了__eq__方法而回傳錯誤的結果,但is保證了你是在跟那個唯一的None物件做比較。
Python 的小把戲:整數與字串的 Interning
有時候,你會發現一些「違背直覺」的現象:1
2
3a = 10
b = 10
print(a is b) # 竟然是 True?
按照前面的邏輯,a 和 b 應該是獨立的物件,為什麼 is 會回傳 True?
這是因為 Python 為了優化效能,會進行 Interning (駐留) 機制。Python 會預先建立好一些常用的物件並重複使用它們(延伸閱讀:Python - 10 is 10 vs 500 is 500):
- 小整數快取: Python 會快取 -5 到 256 之間的所有整數。當你賦值
10時,其實都是指向同一個全域整數物件。 - 字串駐留: 短字串或符合標識符規則的字串也常被 Interning。
字串也有類似的 Interning 機制。符合標識符規則(只含字母、數字、底線)的短字串通常會被自動駐留:1
2
3
4
5
6
7a = "hello"
b = "hello"
print(a is b) # 通常是 True(符合標識符規則,被自動駐留)
a = "hello world"
b = "hello world"
print(a is b) # 通常是 False(含空格,不符合標識符規則)
如果你需要強制讓字串被駐留,可以使用 sys.intern():1
2
3
4
5import sys
a = sys.intern("hello world")
b = sys.intern("hello world")
print(a is b) # True,因為被強制駐留到同一個物件
注意: 在某些 IDE 或編譯後的腳本中,編譯器可能會進行更激進的優化,讓
1000 is 1000也變成True。因此,絕對不要依賴is來比較數值或字串。
總結
| 特性 | == (Equality) | is (Identity) |
|---|---|---|
| 比較對象 | 內容、數值 | 記憶體位址 (id) |
| 底層方法 | __eq__() | 比較 id() |
| 使用時機 | 判斷內容是否相等 | 判斷是否為 None 或同一物件 |
| 常見陷阱 | 無法區分不同記憶體位置 | 易受 Interning 機制誤導 |
記住一個簡單的原則:除非你想檢查「是不是同一個人」,否則請一律使用 ==。 而檢查 None 則是唯一你應該養成習慣使用 is 的地方。