第三章-字串對象
字串對象定義:
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];
} PyStringObject;
由於字串是變長對象,所以有變長對象頭。
ob_shash用來緩衝當前字串的雜湊值,這在以字串作為key的dict物件查詢時非常有用。
ob_sstate用來標記該字串是否為interned。
最後這個ob_sval比較巧妙,定義的是一個字元的數組,他的作用其實是作為實際分配記憶體後,字串緩衝區的指標。在實際給字串對象分配記憶體時,Python申請的記憶體大小為PyStringObject + 字串長度。Python規定字串緩衝區末尾必須是'\0',所以由ob_sval實際指向的緩衝區的長度剛好是length + 1,而ob_sval正好又是字串對象尾部緩衝區的指標。
字串對象的intern機制:
對於相同的兩個字串,Python不會為其建立兩個字串對象,以節省記憶體。intern機制由一個全域的intern字典維護。當建立一個字串時,運行時會在intern字典中查詢是否已經存在這個字串,如果存在,則直接增加字典裡的字串對象的引用計數;如果不存在,則將其添加到字典中。
和整數對象一樣,字串對象同樣有對象池機制提供對ASCII碼對象的快速引用。其原理是,當字串被建立時,PyString_FromString函數會檢查字串長度,如果長度為1,則先建立字串,然後intern字串,最後將字串對象指標儲存在characters對象池中。以後訪問字串,如果長度為1,就直接從對象池中返回對象指標。
關於字串拼接的效率:字串拼接有兩種方式,“+”操作符和str.join(iterable)函數。“+”操作符會調用string_concat函數。它會重新申請一塊記憶體,然後將兩個字串複製到新的記憶體中,返回一個字串對象。也就是說,N個字串拼接會調用N-1次string_concat函數,即申請N-1次記憶體,效率是非常底下的。所以官方推薦str.join(iterable)函數,它接受一個list或tuple等可迭代對象,統計有多少個字串,統一分配一次記憶體,然後複製左右字串到新記憶體中,並返回字串對象。可見後者效率要高很多