關於python整數重用的兩個問題
@
目錄python的整數重用機制
大體可以分為兩部分:
small_ints
連結串列small_ints內儲存著一定範圍的小整數。當有變數引用了範圍內的整數時,就會直接引用此中的地址,而非開闢新地址來儲存資料。
這一範圍可以通過下列程式碼來檢視:
z = []
for i in range(-1000, 1000):
for j in range(-1000, 1000):
if id(i) == id(j):
z.append(i)
print([z[0], z[-1]])
python3.8.3得出的結果是[-5,256]。
也就是說,當以‘=’形式來給變數a、b賦範圍內值時,id(a)==id(b)。
程式碼塊
程式碼塊是程式的一個最小的基本執行單位,一個模組檔案、一個函式體、一個類、互動式命令中的單行程式碼都叫做一個程式碼塊。
Python內部為了進一步提高效能,凡是在一個程式碼塊中建立的整數物件,如果值不在small_ints快取範圍之內,但在同一個程式碼塊中已經存在一個值與其相同的整數物件了,那麼就直接引用該物件,否則建立一個新的物件出來。
需要注意的是,在small_ints範圍外的負數並不適用這一規則。(範圍內的負數浮點數同樣不適用)
問題一:為什麼在vscode中執行程式碼,得到了不符的結果?
下面放一張全圖
問題二:在問題一存在的基礎上,為什麼能測得[-5,256]這一範圍?
其他圖片
vscode已安裝的擴充套件
settings.json
後語
之前接觸到整數快取時曾做過測試,的確與介紹相符。但是,近期卻發現自己測試出了相反的結果,一直不明白哪裡出了問題,因此發到網上來。如有人能指出,不勝感激。
附帶ID為“發黴的宅大人”幫忙提供的版本相關原始碼
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS 257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS 5
#endif
static PyObject * get_small_int(sdigit ival) { PyObject *v; assert(-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS); v = (PyObject *)&small_ints[ival + NSMALLNEGINTS]; Py_INCREF(v); #ifdef COUNT_ALLOCS if (ival >= 0) _Py_quick_int_allocs++; else _Py_quick_neg_int_allocs++; #endif return v; }
2021-1-4
昨天解除安裝並重新安裝了新版本的python、vscode,情況依舊沒有改變。
測試小整數快取表範圍,ok(與之前一樣)。
測試256地址,在不同程式碼塊內保持一致,但每次都不一樣。
測試-6地址,每次都不一樣,但在不同程式碼塊內保持一致。
2021-1-5
在“發黴的宅大人”的建議下,使用IDLE進行測試,以下為測試結果:
使用python直譯器進行測試(不懂得怎麼在定義函式時換行,暫時沒找到教程,因此使用時嘗試了多次,程式碼格式有沒有問題……),以下為測試結果:
顯然,256在不同程式碼塊處於相同的地址中,而257則在不同程式碼中呈現出了兩處地址。這對我來說無疑是個好訊息。
我曾以為,python中的小整數快取表都儲存在固定的地址之中。在直接使用python直譯器執行程式碼沒問題的情況下,我重新取得了256的地址:
256的地址和上面256的地址並不相同,看樣子python會在每次程式碼執行前為處於[-5,256]區間的小整數重新分配地址。
新的問題
將上述問題綜合一下,本文的主要問題變成:
“為什麼vscode、IDLE二者和python直譯器運行同一程式碼會出現不同的結果?是什麼導致了這一區別?”
2021-1-7