Python - 10 is 10 vs 500 is 500
在使用 Python 進行程式設計時,可能會觀察到一種特殊的現象:對於特定範圍內的整數,使用 is
運算子比較兩個賦予相同值的變數會返回 True
,而超出該範圍的整數則返回 False
。
具體示例如下:1
2
3
4
5
6
7
8
9a = 10
b = 10
a is b
True # 嗯,合理!
x = 500
y = 500
x is y
False # WTF???
當變數 a
與 b
均被賦值為 10
時,a is b
的評估結果為 True
。然而,當變數 x
與 y
被賦值為 500
時,x is y
的評估結果卻為 False
,儘管其值相等。此現象並非程式錯誤,而是源於 Python 內部的一種最佳化機制。
本文將扼要地闡釋此最佳化機制背後的原理。

運算子 is 與 == 之區別
首先,我們必須釐清 Python 中兩個重要的比較運算子:is
和 ==
。
== (等於)
:這個運算子檢查的是兩個變數所指向的值 (Value) 是否相等。這是我們最常用來比較數值、字串等內容是否相同的方式。1
2
3
4
5
610 == 10
True
500 == 500
True
"hello" == "hello"
Trueis (是)
:這個運算子檢查的是兩個變數是否指向記憶體中完全相同的物件(Object)。它比較的是物件的識別碼(Identity)。你可以把它想像成檢查兩個變數是不是指向同一個「實體」。我們可以用內建的id()
函數來查看物件在記憶體中的唯一識別碼(在 CPython 中通常是記憶體位址)。1
2
3
4
5
6
7
8
9
10
11
12
13a = [1, 2]
b = [1, 2]
c = a
a == b # 值相等
True
a is b # 但不是同一個物件
False
a is c # a 和 c 指向同一個物件
True
id(a) == id(b)
False
id(a) == id(c)
True
Python 的整數快取機制 (Integer Caching)
釐清 is
與 ==
的功能後,即可理解 500 is 500
為 False
的原因:Python 為這兩個值分別建立了獨立的物件實例。
然而,10 is 10
為何結果為 True
?
答案在於 整數快取 (Integer Caching),亦稱為 小整數物件池 (Small Integer Object Pool)。
此機制為 Python(尤其是標準實作 CPython)為提升執行效能與記憶體利用率而採用的一種最佳化策略:
https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong
- 預先實例化: CPython 在啟動階段會預先建立並儲存一個常用小範圍整數的物件陣列,形成一個快取池。
- 範圍: 這個範圍通常是 -5 到 256 (包含 -5, 256)。
- 重複使用: 當程式碼中需要使用此範圍內的整數時,Python 將直接從快取池中返回對應的已存在物件,而非重複建立新物件。
案例分析
現在,讓我們用整數快取的概念來解釋一開始的現象:
- a = 10, b = 10:
- 10 落在 -5 到 256 的快取範圍內。
- 執行
a = 10
時,a
指向快取池中那個代表 10 的物件。 - 執行
b = 10
時,Python 發現快取池中已經有 10 了,於是讓b
也指向同一個物件。 - 因為
a
和b
指向的是記憶體中完全相同的物件,所以a is b
是True
。 (id(a) 會等於 id(b))
- x = 500, y = 500:
- 500 不在 -5 到 256 的快取範圍內。
- 執行
x = 500
時,Python 必須在記憶體中建立一個新的物件來代表 500。 - 執行
y = 500
時,Python 再次建立另一個新的物件來代表 500。 - 雖然
x
和y
的值都是500
(x == y 為 True),但它們是記憶體中兩個獨立的物件。因此,x is y
是False
。 (id(x) 不等於 id(y))
結論與建議
==
比較值,is
比較物件識別碼 (是否為同一個物件)。- CPython 會快取 -5 到 256 之間的整數物件以進行最佳化。
- 永遠使用 == 來比較數值是否相等。
is
主要用於檢查變數是否指向同一個物件實例,最常見的用途是檢查變數是否為None
(variable isNone
)。
需要注意的是,整數快取行為屬於 CPython 的實作細節 (implementation detail)。雖然 -5
至 256
這一範圍在多數版本中保持穩定,但理論上無法保證在所有 Python 實作或未來版本中維持不變。因此,為確保程式碼的健壯性與可移植性,不應依賴 is
運算子進行數值比較。
本文旨在釐清 Python 中整數比較所觀察到的特殊行為及其背後的機制。理解此差異有助於撰寫更精確且可靠的 Python 程式碼。