您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Python中小整數對象池和字符串intern的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
is用于判斷兩個對象是否為同一個對象,具體來說是兩個對象在內存中的位置是否相同。
python為了提高效率,節省內存,在實現上大量使用了緩沖池技術和字符串intern技術。
整數和字符串是不可變對象,也就意味著可以用來共享,如100個“python”字串變量可以共享一個“python”字符串對象,而不是創建100個“python”字符串。
小整數對象池
為了應對小整數的頻繁使用,python使用對小整數進行了緩存,默認范圍為[-5,256],在這個范圍內的所有整數被python完全地緩存,當有變量使用這些小整數時,增加對應小整數對象的引用即可。
>>> i = -5 >>> j = -5 >>> i is j # i和j是同一個對象 True >>> i = 256 >>> j = 256 >>> i is j # i和j是同一個對象 True >>> i = 257 >>> j = 257 >>> i is j # i和j是不同對象 False
由上面的實例可以看到,當變量在[-5,256]之間時,兩個值相同的變量事實上會引用到同一個小整數對象上,也就是小整數對象池中的對象,而不會去創建兩個對象。而當變量超出了這個范圍,兩個值相同的變量也會各自創建整數對象,所以兩者對應的對象不同。
字符串intern
如果當前變量引用的字符串對象已經存在的話,直接增加對應字符串對象的引用,而不去創建新的字符串對象,這就是字符串intern機制。
>>> i = "12"
>>> j = "12"
>>> i is j
True
在詳細探討字符串intern機制之前,先看一個奇怪的問題:
>>> i = "1 2"
>>> j = "1 2"
>>> i is j
False
i = "1 2"
j = "1 2"
print(i is j)
輸出結果
True
上述代碼分開運行,結果為False,但是合在一起結果卻為True,也就是說分開運行的時候,i,j指向不同對象,而合在一起的時候i,j卻指向了相同對象。為了明白其中的緣由,需要簡單理解python的編譯機制。
編譯機制
在python中,萬物皆對象,包括代碼本身也是一種對象。python用code對象表示代碼,代碼編譯后產生code對象。通常一個作用域對應一個code對象。
i = "1 2" j = "1 2" print(i is j) def f(): pass
編譯結果
2 0 LOAD_CONST 0 ('1 2')
2 STORE_NAME 0 (i)3 4 LOAD_CONST 0 ('1 2')
6 STORE_NAME 1 (j)5 8 LOAD_CONST 1 (<code object f at 0x00000200F257CF60, file "small_int.py", line 5>)
10 LOAD_CONST 2 ('f')
12 MAKE_FUNCTION 0
14 STORE_NAME 2 (f)
16 LOAD_CONST 3 (None)
18 RETURN_VALUEDisassembly of <code object f at 0x00000200F257CF60, file "small_int.py", line 5>:
6 0 LOAD_CONST 0 (None)
2 RETURN_VALUE
上述代碼中編譯生成了兩個code對象,一個代表全局作用域,另一個代表函數f。
code對象保存了變量,常量(常量字面量)以及編譯結果。code對象用常量表來保存常量,考慮到一個常量可能出現多次,在一張表上保存一個常量多次太過于奢侈。所以code對象對每個常量只保存一次,在需要引用它的地方使用它在常量表的位置作為常量的表示。在上述編譯結果中可以看到,"1 2"這個字符串常量使用了兩次,編譯的代碼為"LOAD_CONST 0",這里的0就是"1 2"在常量表當中的位置。
由于編譯的這個特性,在同一個code對象中的變量,如果它們引用了同一個常量,那么無論這個常量有沒有緩沖機制,它們引用的都是同一個對象。
a = "12" b = "12" c = "1 2" d = "1 2" e = 257 f = 257 g = 2424234234234234 h = 2424234234234234 print(a is b, c is d, e is f, g is h)
輸出結果
True True True True
這個例子說明,在同一個code對象當中,常量(字面量)僅一份,這與緩沖機制無關,是編譯特性。所以對于上述那個奇怪的問題就可以解釋了,當i,j在同一個code對象(同一個作用域)中引用常量"1 2",它們引用的都是同一個對象。而當在python命令行中分開執行時,對于每一條語句,都是一個單獨的code對象,這時起作用的是字符串intern機制,上述運行結果說明,字符串intern機制對"12"進行了intern,而對"1 2"沒有進行intern。
編譯機制與小整數對象池對比
i = 257 j = 257 a = i - 1 b = i - 1 c = i + 1 d = i + 1 print(i is j, a is b, c is d)
輸出結果
True True False
i和j引用同一個常量,這是編譯機制,所以i與j指向同一個整數對象,后面a和b雖然相等,但不引用常量,此時啟用小整數對象池,a,b都等于256,在對象池中,所以a,b引用同一個對象,后面c,d不在對象池中,所以兩者對象不同。
這里有一點需要注意,沒有變量參與的運算會被編譯器直接優化成對應的常量,進而保存進常量表中。
字符串intern機制與字符緩沖池
在編譯過程中,字符串intern機制將所有的變量名進行intern,但對常量進行的intern有一點特殊的限制。能夠intern的常量必須只包含[a-zA-Z0-9_],即字母數字加下劃線,如果含有其他字符,就不會intern。在運行過程中,通過計算得到的字符串不會intern。
字符串有一個和小整數對象池相似的字符緩沖池,用于在運行過程中緩存單個字符,所以計算得到的字符串雖然不會intern,但如果是單個字符,就會使用到字符緩沖池。
k = "bbb" a = k[0] b = k[0] c = k[1:] d = k[1:] print(a, d) print(a is b, c is d)
輸出結果
b bb
True False
可以看到,a和b確實指向同一個對象,而c和d指向不同對象,這就是字符緩沖池。
編譯機制與字符串intern對比
i = "1 2" j = "12" k = "__fjdslfjaskfas" ii = "1 2" jj = "12" kk = "__fjdslfjaskfas" def f(): a = "1 2" b = "12" c = "__fjdslfjaskfas" return a is i, b is j, c is k print("Code:", i is ii, j is jj, k is kk) print(f"intern: {f()}")
輸出結果
Code: True True True
intern: (False, True, True)
i包含空格,包含空格的常量不會被intern,而其他兩個常量不包含其他字符,所以會被intern。
總結
1. python代碼被編譯成code對象,通常一個code對象對應于一個作用域,作用域中重復出現的變量名以及常量在code中只保存一次。
2. 字符串intern機制主要作用于編譯過程,在編譯收集完變量和常量時,對變量和常量進行intern,而后構建一個code對象。
3. 字符串intern對常量的intern有限制,能夠intern的常量必須只包含[a-zA-Z0-9_],即字母數字加下劃線,如果含有其他字符,就不會intern。
4. 小整數對象池和字符緩沖池都是作用于運行過程中,python緩存小的整數和字符,當有變量使用這些對象時,不用額外創建對象。
1、簡單易用,與C/C++、Java、C# 等傳統語言相比,Python對代碼格式的要求沒有那么嚴格;2、Python屬于開源的,所有人都可以看到源代碼,并且可以被移植在許多平臺上使用;3、Python面向對象,能夠支持面向過程編程,也支持面向對象編程;4、Python是一種解釋性語言,Python寫的程序不需要編譯成二進制代碼,可以直接從源代碼運行程序;5、Python功能強大,擁有的模塊眾多,基本能夠實現所有的常見功能。
關于“Python中小整數對象池和字符串intern的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。