Python 的 String Interning 機制

Python 的 String Interning 機制

許多程式語言會使用 2 個等號 == 比較兩個值是否相等,在 Python 也是一樣,但 Python 還有個特別的比較方法 is,它可以用來比較這兩個值是不是同一個物件:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a == b
True
>>> a is b
False

雖然變數 ab 看起來都是串列 [1, 2, 3],但實際上它們在 Python 是兩個不同的東西,你可以想像成我們從網路上買了兩盒一樣的玩具,如果沒有特別的碰撞或破損的話,這兩盒玩具的包裝盒看起來都一樣,裡面的玩具看起來也是一樣,但這兩個玩具本質上就是兩個不同的玩具。在 Python 有個叫做 id() 的內建函數,可以用來查看某個東西在 Python 世界裡的「編號」:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a)
4303554880
>>> id(b)
4303556672

可以看的出來這兩個串列雖然看起來一樣,但內部的編號是不同的。再來給大家看一個例子:

>>> a = [1, 2, 3]
>>> b = a
>>> a == b
True
>>> a is b
True

第二行的 b = a 的意思,就是把 a 的值指派給 b,所以這時候不管是 ab 都是指向同一個地方,它們的 id() 函數的執行結果也會一樣,所以 a is b 會是 True。到這裡應該還算容易理解,接著來看比較難一點的:

a = "hellokitty"
b = "hellokitty"
print(a == b) # 印出什麼?
print(a is b) # 印出什麼?

猜猜看,你覺得會印出什麼結果?== 的比較容易猜,就是比對這兩個變數的值是不是一樣,所以會得到 True。而 is 會比較這兩個 "hellokitty" 字串是不是同一個,這在其它的程式語言可能會有不同的結果,我用 Ruby 舉個例子:

>> a = "hellokitty"
>> b = "hellokitty"
>> a.object_id
=> 47540
>> b.object_id
=> 56940

這裡的 .object_id 方法跟剛剛提到的 id() 函數的功能差不多,在 Ruby 裡的字串雖然看起來一樣,但它們實際上在記憶體裡就是兩個不同的東西。這在 Python 裡會有不同的結果,還記得我們在上個章節才講到 Python 的字串本身的設計是不可變(Immutable)的嗎?既然不能變,所以 Python 內部會建立一個「表格」用來存放一些字串,試著盡可能的把同樣的字串建放同一個地方,以節省一些記憶體空間,這個機制叫做 String Interning(有興趣去翻 Python 的原始碼就會發現這個「表格」本質上是一個字典)。當你試著把一個字串被被命名為某個變數的時候,Python 會決定要不要使用之前曾經使用過的字串。

>>> id("hellokitty")
4305320112
>>> id("hellokitty")
4305320112
>>> id("hellokitty")
4305320112

但也不是所有的字串都會走這個機制,例如這個例子:

>>> id("hello kitty")
4305197104
>>> id("hello kitty")
4305197424
>>> id("hello kitty")
4305195568

String Interning 機制主要會發生在幾個情況,只有字數比較少而且只包含英文字母、數字、底線的字串才會幫我們處理,在上面這個範例中的字串有空白字元,Python 就沒有幫我們保留下來,而是每次都會產生一個新的字串。如果你想要強制讓 Python 發動 String Interning 機制的話,可使用內建模組 sysintern() 函數:

>>> import sys
>>> a = sys.intern("hello kitty")
>>> b = sys.intern("hello kitty")
>>> a is b
True

不只字串,數字也有類似的機制,但這個機制不會無限上綱到所有的數字,只有在 -5256 之間的整數才會發生:

>>> a = 256
>>> b = 256
>>> a is b
True

# 超過範圍了
>>> a = 257
>>> b = 257
>>> a is b
False

因為 -5 到 256 之間的數字很常用到,所以 Python 在啟動的時候有先幫我們就把這些數字先準備好,如果在程式裡用到的話就不用另外重新產生一份。

工商:想學 Python 嗎?我教你啊!

想要成為軟體工程師嗎?這不是條輕鬆的路,需要有足夠的決心、設定目標並持續學習,我們的 ASTROCamp 軟體工程師培訓營提供專業的前後端課程培訓,幫助你在最短時間內建立正確且扎實的軟體開發技能,有興趣而且不怕吃苦的話不妨來試試看吧 :)