1. 程式人生 > 實用技巧 >關於python整數重用的兩個問題

關於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